From 22e91207d3024ae49f88f9b002de84891760d17f Mon Sep 17 00:00:00 2001 From: DoHyun Pyun Date: Wed, 25 Mar 2020 15:57:14 +0900 Subject: [PATCH] Use the external ell package Change-Id: Ibbc87d87131a5b4abcb6dc48eb8232df43566218 Signed-off-by: DoHyun Pyun --- ell/asn1-private.h | 203 ---- ell/base64.c | 173 --- ell/base64.h | 37 - ell/cert-private.h | 30 - ell/cert.c | 559 --------- ell/cert.h | 66 -- ell/checksum.c | 491 -------- ell/checksum.h | 75 -- ell/cipher.c | 664 ----------- ell/cipher.h | 94 -- ell/dbus-client.c | 733 ------------ ell/dbus-client.h | 98 -- ell/dbus-filter.c | 423 ------- ell/dbus-message.c | 1991 ------------------------------- ell/dbus-name-cache.c | 307 ----- ell/dbus-private.h | 308 ----- ell/dbus-service.c | 2102 --------------------------------- ell/dbus-service.h | 93 -- ell/dbus-util.c | 1305 -------------------- ell/dbus.c | 1814 ---------------------------- ell/dbus.h | 277 ----- ell/dhcp-lease.c | 226 ---- ell/dhcp-private.h | 127 -- ell/dhcp-transport.c | 527 --------- ell/dhcp.c | 1277 -------------------- ell/dhcp.h | 106 -- ell/dir.c | 350 ------ ell/dir.h | 54 - ell/ecc-external.c | 951 --------------- ell/ecc-private.h | 99 -- ell/ecc.c | 760 ------------ ell/ecc.h | 103 -- ell/ecdh.c | 107 -- ell/ecdh.h | 53 - ell/ell.h | 64 - ell/file.c | 89 -- ell/file.h | 36 - ell/genl-private.h | 27 - ell/genl.c | 2062 -------------------------------- ell/genl.h | 146 --- ell/gpio.c | 400 ------- ell/gpio.h | 70 -- ell/gvariant-private.h | 69 -- ell/gvariant-util.c | 1384 ---------------------- ell/hashmap.c | 653 ---------- ell/hashmap.h | 78 -- ell/hwdb.c | 380 ------ ell/hwdb.h | 63 - ell/idle.c | 165 --- ell/idle.h | 49 - ell/io.c | 409 ------- ell/io.h | 62 - ell/key.c | 818 ------------- ell/key.h | 128 -- ell/log.c | 457 ------- ell/log.h | 101 -- ell/main.c | 665 ----------- ell/main.h | 51 - ell/missing.h | 64 - ell/net.c | 112 -- ell/net.h | 40 - ell/netlink-private.h | 25 - ell/netlink.c | 613 ---------- ell/netlink.h | 66 -- ell/path.c | 187 --- ell/path.h | 39 - ell/pem-private.h | 34 - ell/pem.c | 558 --------- ell/pem.h | 57 - ell/pkcs5-private.h | 25 - ell/pkcs5.c | 490 -------- ell/pkcs5.h | 47 - ell/plugin.c | 219 ---- ell/plugin.h | 78 -- ell/private.h | 56 - ell/queue.c | 589 --------- ell/queue.h | 82 -- ell/random.c | 107 -- ell/random.h | 43 - ell/ringbuf.c | 422 ------- ell/ringbuf.h | 65 - ell/settings.c | 1437 ---------------------- ell/settings.h | 137 --- ell/signal.c | 270 ----- ell/signal.h | 45 - ell/siphash-private.h | 27 - ell/siphash.c | 138 --- ell/string.c | 518 -------- ell/string.h | 58 - ell/strv.c | 363 ------ ell/strv.h | 50 - ell/test.c | 129 -- ell/test.h | 42 - ell/time.c | 72 -- ell/time.h | 81 -- ell/timeout.c | 315 ----- ell/timeout.h | 55 - ell/tls-extensions.c | 907 -------------- ell/tls-private.h | 360 ------ ell/tls-record.c | 643 ---------- ell/tls-suites.c | 1373 --------------------- ell/tls.c | 3078 ------------------------------------------------ ell/tls.h | 141 --- ell/uintset.c | 532 --------- ell/uintset.h | 66 -- ell/utf8.c | 497 -------- ell/utf8.h | 120 -- ell/util.c | 638 ---------- ell/util.h | 318 ----- ell/uuid.c | 260 ---- ell/uuid.h | 62 - packaging/bluez.spec | 10 +- 112 files changed, 7 insertions(+), 41762 deletions(-) delete mode 100644 ell/asn1-private.h delete mode 100644 ell/base64.c delete mode 100644 ell/base64.h delete mode 100644 ell/cert-private.h delete mode 100644 ell/cert.c delete mode 100644 ell/cert.h delete mode 100644 ell/checksum.c delete mode 100644 ell/checksum.h delete mode 100644 ell/cipher.c delete mode 100644 ell/cipher.h delete mode 100644 ell/dbus-client.c delete mode 100644 ell/dbus-client.h delete mode 100644 ell/dbus-filter.c delete mode 100644 ell/dbus-message.c delete mode 100644 ell/dbus-name-cache.c delete mode 100644 ell/dbus-private.h delete mode 100644 ell/dbus-service.c delete mode 100644 ell/dbus-service.h delete mode 100644 ell/dbus-util.c delete mode 100644 ell/dbus.c delete mode 100644 ell/dbus.h delete mode 100644 ell/dhcp-lease.c delete mode 100644 ell/dhcp-private.h delete mode 100644 ell/dhcp-transport.c delete mode 100644 ell/dhcp.c delete mode 100644 ell/dhcp.h delete mode 100644 ell/dir.c delete mode 100644 ell/dir.h delete mode 100644 ell/ecc-external.c delete mode 100644 ell/ecc-private.h delete mode 100644 ell/ecc.c delete mode 100644 ell/ecc.h delete mode 100644 ell/ecdh.c delete mode 100644 ell/ecdh.h delete mode 100644 ell/ell.h delete mode 100644 ell/file.c delete mode 100644 ell/file.h delete mode 100644 ell/genl-private.h delete mode 100644 ell/genl.c delete mode 100644 ell/genl.h delete mode 100644 ell/gpio.c delete mode 100644 ell/gpio.h delete mode 100644 ell/gvariant-private.h delete mode 100644 ell/gvariant-util.c delete mode 100644 ell/hashmap.c delete mode 100644 ell/hashmap.h delete mode 100644 ell/hwdb.c delete mode 100644 ell/hwdb.h delete mode 100644 ell/idle.c delete mode 100644 ell/idle.h delete mode 100644 ell/io.c delete mode 100644 ell/io.h delete mode 100644 ell/key.c delete mode 100644 ell/key.h delete mode 100644 ell/log.c delete mode 100644 ell/log.h delete mode 100644 ell/main.c delete mode 100644 ell/main.h delete mode 100644 ell/missing.h delete mode 100644 ell/net.c delete mode 100644 ell/net.h delete mode 100644 ell/netlink-private.h delete mode 100644 ell/netlink.c delete mode 100644 ell/netlink.h delete mode 100644 ell/path.c delete mode 100644 ell/path.h delete mode 100644 ell/pem-private.h delete mode 100644 ell/pem.c delete mode 100644 ell/pem.h delete mode 100644 ell/pkcs5-private.h delete mode 100644 ell/pkcs5.c delete mode 100644 ell/pkcs5.h delete mode 100644 ell/plugin.c delete mode 100644 ell/plugin.h delete mode 100644 ell/private.h delete mode 100644 ell/queue.c delete mode 100644 ell/queue.h delete mode 100644 ell/random.c delete mode 100644 ell/random.h delete mode 100644 ell/ringbuf.c delete mode 100644 ell/ringbuf.h delete mode 100644 ell/settings.c delete mode 100644 ell/settings.h delete mode 100644 ell/signal.c delete mode 100644 ell/signal.h delete mode 100644 ell/siphash-private.h delete mode 100644 ell/siphash.c delete mode 100644 ell/string.c delete mode 100644 ell/string.h delete mode 100644 ell/strv.c delete mode 100644 ell/strv.h delete mode 100644 ell/test.c delete mode 100644 ell/test.h delete mode 100644 ell/time.c delete mode 100644 ell/time.h delete mode 100644 ell/timeout.c delete mode 100644 ell/timeout.h delete mode 100644 ell/tls-extensions.c delete mode 100644 ell/tls-private.h delete mode 100644 ell/tls-record.c delete mode 100644 ell/tls-suites.c delete mode 100644 ell/tls.c delete mode 100644 ell/tls.h delete mode 100644 ell/uintset.c delete mode 100644 ell/uintset.h delete mode 100644 ell/utf8.c delete mode 100644 ell/utf8.h delete mode 100644 ell/util.c delete mode 100644 ell/util.h delete mode 100644 ell/uuid.c delete mode 100644 ell/uuid.h diff --git a/ell/asn1-private.h b/ell/asn1-private.h deleted file mode 100644 index e34f977..0000000 --- a/ell/asn1-private.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Embedded Linux library - * - * Copyright (C) 2017 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#define ASN1_ID(class, pc, tag) (((class) << 6) | ((pc) << 5) | (tag)) - -#define ASN1_CLASS_UNIVERSAL 0 -#define ASN1_CLASS_CONTEXT 2 - -#define ASN1_ID_SEQUENCE ASN1_ID(ASN1_CLASS_UNIVERSAL, 1, 0x10) -#define ASN1_ID_SET ASN1_ID(ASN1_CLASS_UNIVERSAL, 1, 0x11) -#define ASN1_ID_BOOLEAN ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x01) -#define ASN1_ID_INTEGER ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x02) -#define ASN1_ID_BIT_STRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x03) -#define ASN1_ID_OCTET_STRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x04) -#define ASN1_ID_OID ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x06) -#define ASN1_ID_UTF8STRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x0c) -#define ASN1_ID_PRINTABLESTRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x13) -#define ASN1_ID_IA5STRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x16) - -struct asn1_oid { - uint8_t asn1_len; - uint8_t asn1[10]; -}; - -#define asn1_oid_eq(oid1, oid2_len, oid2_string) \ - ((oid1)->asn1_len == (oid2_len) && \ - !memcmp((oid1)->asn1, (oid2_string), (oid2_len))) - -#if __STDC_VERSION__ <= 199409L -#define inline __inline__ -#endif - -static inline int asn1_parse_definite_length(const uint8_t **buf, - size_t *len) -{ - int n; - size_t result = 0; - - /* Decrease the buffer length left */ - if ((*len)-- < 1) - return -1; - - /* - * If short form length, move the pointer to start of data and - * return the data length. - */ - if (!(**buf & 0x80)) - return *(*buf)++; - - n = *(*buf)++ & 0x7f; - if ((size_t) n > *len) - return -1; - - *len -= n; - while (n--) - result = (result << 8) | *(*buf)++; - - return result; -} - -static inline void asn1_write_definite_length(uint8_t **buf, size_t len) -{ - int n; - - if (len < 0x80) { - *(*buf)++ = len; - return; - } - - for (n = 1; len >> (n * 8); n++); - *(*buf)++ = 0x80 | n; - - while (n--) - *(*buf)++ = len >> (n * 8); -} - -#define ASN1_CONTEXT_IMPLICIT(tag) (0x1000 | (tag)) -#define ASN1_CONTEXT_EXPLICIT(tag) (0x2000 | (tag)) - -/* - * Return the tag, length and value of the @index'th - * non-context-specific-tagged element in a DER SEQUENCE or one who's - * ASN1_CONTEXT_IMPLICIT(tag) matches @index or the inner element of - * the one who's ASN1_CONTEXT_EXPLICIT(tag) matches @index. - */ -static inline const uint8_t *asn1_der_find_elem(const uint8_t *buf, - size_t len_in, int index, - uint8_t *tag, size_t *len_out) -{ - int n = 0; - - while (1) { - int tlv_len; - - if (len_in < 2) - return NULL; - - *tag = *buf++; - len_in--; - - tlv_len = asn1_parse_definite_length((void *) &buf, &len_in); - if (tlv_len < 0 || (size_t) tlv_len > len_in) - return NULL; - - if (*tag >> 6 != ASN1_CLASS_CONTEXT) { - if (n++ == index) { - *len_out = tlv_len; - return buf; - } - } else if ((*tag & 0x1f) == (index & 0xfff)) { - /* Context-specific tag */ - if (index & 0x1000) { /* Implicit */ - *len_out = tlv_len; - return buf; - } else if (index & 0x2000) { /* Explicit */ - const uint8_t *outer = buf; - int inner_len; - - if (!(*tag & 0x20)) /* Primitive */ - return NULL; - - if (unlikely(tlv_len < 2)) - return NULL; - - *tag = *buf++; - - inner_len = asn1_parse_definite_length( - (void *) &buf, &len_in); - if (outer + tlv_len != buf + inner_len) - return NULL; - - *len_out = inner_len; - return buf; - } - } - - buf += tlv_len; - len_in -= tlv_len; - } -} - -/* Return an element in a DER SEQUENCE structure by path */ -static inline const uint8_t *asn1_der_find_elem_by_path(const uint8_t *buf, - size_t len_in, uint8_t tag, - size_t *len_out, ...) -{ - int index; - va_list vl; - - va_start(vl, len_out); - - index = va_arg(vl, int); - - while (index != -1) { - uint8_t elem_tag; - uint8_t expect_tag; - int prev_index = index; - - buf = asn1_der_find_elem(buf, len_in, index, - &elem_tag, &len_in); - if (!buf) { - va_end(vl); - return NULL; - } - - index = va_arg(vl, int); - - if (prev_index & 0x1000) - expect_tag = ASN1_ID(ASN1_CLASS_CONTEXT, - index != -1 ? 1 : - ((elem_tag >> 5) & 1), - prev_index & 0xfff); - else - expect_tag = (index == -1) ? tag : ASN1_ID_SEQUENCE; - - if (elem_tag != expect_tag) { - va_end(vl); - return NULL; - } - } - - va_end(vl); - - *len_out = len_in; - return buf; -} diff --git a/ell/base64.c b/ell/base64.c deleted file mode 100644 index c241869..0000000 --- a/ell/base64.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Embedded Linux library - * - * Copyright (C) 2015 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "utf8.h" -#include "base64.h" -#include "private.h" - -LIB_EXPORT uint8_t *l_base64_decode(const char *in, size_t in_len, - size_t *n_written) -{ - const char *ptr, *in_end = in + in_len; - uint8_t *out_buf, *out; - int base64_len = 0, pad_len; - uint16_t reg = 0; - - for (ptr = in; ptr < in_end; ptr++) - if (l_ascii_isspace(*ptr)) - /* Whitespace */ - continue; - else if (*ptr == '=') - /* Final padding */ - break; - else if (l_ascii_isalnum(*ptr) || *ptr == '+' || *ptr == '/') - /* Base64 character */ - base64_len++; - else - /* Bad character */ - return NULL; - - in_end = ptr; - - if ((base64_len & 3) == 1) - /* Invalid length */ - return NULL; - - pad_len = (4 - base64_len) & 3; - for (; ptr < in + in_len && pad_len; ptr++) - if (l_ascii_isspace(*ptr)) - /* Whitespace */ - continue; - else if (*ptr == '=') - /* Final padding */ - pad_len--; - else - /* Bad character */ - return NULL; - if (pad_len) - return NULL; - - *n_written = base64_len * 3 / 4; - out_buf = l_malloc(*n_written); - - out = out_buf; - base64_len = 0; - - for (ptr = in; ptr < in_end; ptr++) { - if (l_ascii_isspace(*ptr)) - /* Whitespace */ - continue; - - /* Base64 character */ - reg <<= 6; - if (l_ascii_isupper(*ptr)) - reg |= *ptr - 'A' + 0; - else if (l_ascii_islower(*ptr)) - reg |= *ptr - 'a' + 26; - else if (l_ascii_isdigit(*ptr)) - reg |= *ptr - '0' + 52; - else if (*ptr == '+') - reg |= 62; - else if (*ptr == '/') - reg |= 63; - - if ((base64_len & 3) == 1) - *out++ = reg >> 4; - else if ((base64_len & 3) == 2) - *out++ = reg >> 2; - else if ((base64_len & 3) == 3) - *out++ = reg >> 0; - - base64_len++; - } - - return out_buf; -} - -LIB_EXPORT char *l_base64_encode(const uint8_t *in, size_t in_len, - int columns, size_t *n_written) -{ - const uint8_t *in_end = in + in_len; - char *out_buf, *out; - size_t out_len; - uint32_t reg; - uint8_t idx; - int i, pad = 4; - int col = 0; - - /* For simplicity allow multiples of 4 only */ - if (columns & 3) - return NULL; - - out_len = (in_len + 2) / 3 * 4; - - if (columns && out_len) - out_len += (out_len - 4) / columns; - - out_buf = l_malloc(out_len); - *n_written = out_len; - - out = out_buf; - - while (in < in_end) { - reg = *in++ << 16; - - if (in < in_end) - reg |= *in++ << 8; - else - pad--; - - if (in < in_end) - reg |= *in++ << 0; - else - pad--; - - if (columns && col == columns) { - *out++ = '\n'; - col = 0; - } - col += 4; - - for (i = 0; i < pad; i++) { - idx = (reg >> 18) & 63; - reg <<= 6; - - if (idx < 26) - *out++ = idx + 'A'; - else if (idx < 52) - *out++ = idx - 26 + 'a'; - else if (idx < 62) - *out++ = idx - 52 + '0'; - else - *out++ = (idx == 62) ? '+' : '/'; - } - } - - for (; pad < 4; pad++) - *out++ = '='; - - return out_buf; -} diff --git a/ell/base64.h b/ell/base64.h deleted file mode 100644 index 74dae8f..0000000 --- a/ell/base64.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Embedded Linux library - * - * Copyright (C) 2015 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __ELL_BASE64_H -#define __ELL_BASE64_H - -#ifdef __cplusplus -extern "C" { -#endif - -uint8_t *l_base64_decode(const char *in, size_t in_len, size_t *n_written); - -char *l_base64_encode(const uint8_t *in, size_t in_len, int columns, - size_t *n_written); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_BASE64_H */ diff --git a/ell/cert-private.h b/ell/cert-private.h deleted file mode 100644 index ba9a513..0000000 --- a/ell/cert-private.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -struct asn1_oid; - -struct l_certchain *certchain_new_from_leaf(struct l_cert *leaf); -void certchain_link_issuer(struct l_certchain *chain, struct l_cert *issuer); - -const uint8_t *cert_get_extension(struct l_cert *cert, - const struct asn1_oid *ext_id, - bool *out_critical, size_t *out_len); diff --git a/ell/cert.c b/ell/cert.c deleted file mode 100644 index d1f58d7..0000000 --- a/ell/cert.c +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "private.h" -#include "key.h" -#include "queue.h" -#include "asn1-private.h" -#include "cert.h" -#include "cert-private.h" - -#define X509_CERTIFICATE_POS 0 -#define X509_TBSCERTIFICATE_POS 0 -#define X509_TBSCERT_VERSION_POS ASN1_CONTEXT_EXPLICIT(0) -#define X509_TBSCERT_SERIAL_POS 0 -#define X509_TBSCERT_SIGNATURE_POS 1 -#define X509_ALGORITHM_ID_ALGORITHM_POS 0 -#define X509_ALGORITHM_ID_PARAMS_POS 1 -#define X509_TBSCERT_ISSUER_DN_POS 2 -#define X509_TBSCERT_VALIDITY_POS 3 -#define X509_TBSCERT_SUBJECT_DN_POS 4 -#define X509_TBSCERT_SUBJECT_KEY_POS 5 -#define X509_SUBJECT_KEY_ALGORITHM_POS 0 -#define X509_SUBJECT_KEY_VALUE_POS 1 -#define X509_TBSCERT_ISSUER_UID_POS ASN1_CONTEXT_IMPLICIT(1) -#define X509_TBSCERT_SUBJECT_UID_POS ASN1_CONTEXT_IMPLICIT(2) -#define X509_TBSCERT_EXTENSIONS_POS ASN1_CONTEXT_EXPLICIT(3) -#define X509_SIGNATURE_ALGORITHM_POS 1 -#define X509_SIGNATURE_VALUE_POS 2 - -struct l_cert { - enum l_cert_key_type pubkey_type; - struct l_cert *issuer; - struct l_cert *issued; - size_t asn1_len; - uint8_t asn1[0]; -}; - -struct l_certchain { - struct l_cert *leaf; /* Bottom of the doubly-linked list */ - struct l_cert *ca; /* Top of the doubly-linked list */ -}; - -static const struct pkcs1_encryption_oid { - enum l_cert_key_type key_type; - struct asn1_oid oid; -} pkcs1_encryption_oids[] = { - { /* rsaEncryption */ - L_CERT_KEY_RSA, - { 9, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 } }, - }, -}; - -static bool cert_set_pubkey_type(struct l_cert *cert) -{ - const uint8_t *key_type; - size_t key_type_len; - int i; - - key_type = asn1_der_find_elem_by_path(cert->asn1, cert->asn1_len, - ASN1_ID_OID, &key_type_len, - X509_CERTIFICATE_POS, - X509_TBSCERTIFICATE_POS, - X509_TBSCERT_SUBJECT_KEY_POS, - X509_SUBJECT_KEY_ALGORITHM_POS, - X509_ALGORITHM_ID_ALGORITHM_POS, - -1); - if (!key_type) - return false; - - for (i = 0; i < (int) L_ARRAY_SIZE(pkcs1_encryption_oids); i++) - if (asn1_oid_eq(&pkcs1_encryption_oids[i].oid, - key_type_len, key_type)) - break; - - if (i == L_ARRAY_SIZE(pkcs1_encryption_oids)) - cert->pubkey_type = L_CERT_KEY_UNKNOWN; - else - cert->pubkey_type = pkcs1_encryption_oids[i].key_type; - - return true; -} - -LIB_EXPORT struct l_cert *l_cert_new_from_der(const uint8_t *buf, - size_t buf_len) -{ - const uint8_t *seq = buf; - size_t seq_len = buf_len; - size_t content_len; - struct l_cert *cert; - - /* Sanity check: outer element is a SEQUENCE */ - if (seq_len-- < 1 || *seq++ != ASN1_ID_SEQUENCE) - return NULL; - - /* Sanity check: the SEQUENCE spans the whole buffer */ - content_len = asn1_parse_definite_length(&seq, &seq_len); - if (content_len < 64 || content_len != seq_len) - return NULL; - - /* - * We could require the signature algorithm and the key algorithm - * to be one of our supported types here but instead we only - * require that when the user wants to verify this certificate or - * get the public key respectively. - */ - - cert = l_malloc(sizeof(struct l_cert) + buf_len); - cert->issuer = NULL; - cert->issued = NULL; - cert->asn1_len = buf_len; - memcpy(cert->asn1, buf, buf_len); - - /* Sanity check: structure is correct up to the Public Key Algorithm */ - if (!cert_set_pubkey_type(cert)) { - l_free(cert); - return NULL; - } - - return cert; -} - -LIB_EXPORT void l_cert_free(struct l_cert *cert) -{ - l_free(cert); -} - -LIB_EXPORT const uint8_t *l_cert_get_der_data(struct l_cert *cert, - size_t *out_len) -{ - if (unlikely(!cert)) - return NULL; - - *out_len = cert->asn1_len; - return cert->asn1; -} - -LIB_EXPORT const uint8_t *l_cert_get_dn(struct l_cert *cert, size_t *out_len) -{ - if (unlikely(!cert)) - return NULL; - - return asn1_der_find_elem_by_path(cert->asn1, cert->asn1_len, - ASN1_ID_SEQUENCE, out_len, - X509_CERTIFICATE_POS, - X509_TBSCERTIFICATE_POS, - X509_TBSCERT_SUBJECT_DN_POS, - -1); -} - -const uint8_t *cert_get_extension(struct l_cert *cert, - const struct asn1_oid *ext_id, - bool *out_critical, size_t *out_len) -{ - const uint8_t *ext, *end; - size_t ext_len; - - if (unlikely(!cert)) - return NULL; - - ext = asn1_der_find_elem_by_path(cert->asn1, cert->asn1_len, - ASN1_ID_SEQUENCE, &ext_len, - X509_CERTIFICATE_POS, - X509_TBSCERTIFICATE_POS, - X509_TBSCERT_EXTENSIONS_POS, - -1); - if (unlikely(!ext)) - return NULL; - - end = ext + ext_len; - while (ext < end) { - const uint8_t *seq, *oid, *data; - uint8_t tag; - size_t len, oid_len, data_len; - bool critical; - - seq = asn1_der_find_elem(ext, end - ext, 0, &tag, &len); - if (unlikely(!seq || tag != ASN1_ID_SEQUENCE)) - return false; - - ext = seq + len; - - oid = asn1_der_find_elem(seq, len, 0, &tag, &oid_len); - if (unlikely(!oid || tag != ASN1_ID_OID)) - return false; - - if (!asn1_oid_eq(ext_id, oid_len, oid)) - continue; - - data = asn1_der_find_elem(seq, len, 1, &tag, &data_len); - critical = false; - - if (data && tag == ASN1_ID_BOOLEAN) { - if (data_len != 1) - return false; - - critical = *data != 0; /* Tolerate BER booleans */ - - data = asn1_der_find_elem(seq, len, 2, &tag, &data_len); - } - - if (unlikely(!data || tag != ASN1_ID_OCTET_STRING)) - return false; - - if (out_critical) - *out_critical = critical; - - if (out_len) - *out_len = data_len; - - return data; - } - - return NULL; -} - -LIB_EXPORT enum l_cert_key_type l_cert_get_pubkey_type(struct l_cert *cert) -{ - if (unlikely(!cert)) - return L_CERT_KEY_UNKNOWN; - - return cert->pubkey_type; -} - -/* - * Note: Returns a new l_key object to be freed by the caller. - */ -LIB_EXPORT struct l_key *l_cert_get_pubkey(struct l_cert *cert) -{ - if (unlikely(!cert)) - return NULL; - - /* Use kernel's ASN.1 certificate parser to find the key data for us */ - if (cert->pubkey_type == L_CERT_KEY_RSA) - return l_key_new(L_KEY_RSA, cert->asn1, cert->asn1_len); - - return NULL; -} - -/* - * Note: takes ownership of the certificate. The certificate is - * assumed to be new and not linked into any certchain object. - */ -struct l_certchain *certchain_new_from_leaf(struct l_cert *leaf) -{ - struct l_certchain *chain; - - chain = l_new(struct l_certchain, 1); - chain->leaf = leaf; - chain->ca = leaf; - return chain; -} - -/* - * Note: takes ownership of the certificate. The certificate is - * assumed to be new and not linked into any certchain object. - */ -void certchain_link_issuer(struct l_certchain *chain, struct l_cert *ca) -{ - ca->issued = chain->ca; - chain->ca->issuer = ca; - chain->ca = ca; -} - -static struct l_cert *certchain_pop_ca(struct l_certchain *chain) -{ - struct l_cert *ca = chain->ca; - - if (!ca) - return NULL; - - if (ca->issued) { - chain->ca = ca->issued; - ca->issued->issuer = NULL; - ca->issued = NULL; - } else { - chain->ca = NULL; - chain->leaf = NULL; - } - - return ca; -} - -LIB_EXPORT void l_certchain_free(struct l_certchain *chain) -{ - while (chain && chain->ca) - l_cert_free(certchain_pop_ca(chain)); - - l_free(chain); -} - -LIB_EXPORT struct l_cert *l_certchain_get_leaf(struct l_certchain *chain) -{ - if (unlikely(!chain)) - return NULL; - - return chain->leaf; -} - -/* - * Call @cb for each certificate in the chain starting from the leaf - * certificate. Stop if a call returns @true. - */ -LIB_EXPORT void l_certchain_walk_from_leaf(struct l_certchain *chain, - l_cert_walk_cb_t cb, - void *user_data) -{ - struct l_cert *cert; - - if (unlikely(!chain)) - return; - - for (cert = chain->leaf; cert; cert = cert->issuer) - if (cb(cert, user_data)) - break; -} - -/* - * Call @cb for each certificate in the chain starting from the root - * certificate. Stop if a call returns @true. - */ -LIB_EXPORT void l_certchain_walk_from_ca(struct l_certchain *chain, - l_cert_walk_cb_t cb, - void *user_data) -{ - struct l_cert *cert; - - if (unlikely(!chain)) - return; - - for (cert = chain->ca; cert; cert = cert->issued) - if (cb(cert, user_data)) - break; -} - -static struct l_keyring *cert_set_to_keyring(struct l_queue *certs, char *error) -{ - struct l_keyring *ring; - const struct l_queue_entry *entry; - int i = 1; - - ring = l_keyring_new(); - if (!ring) - return NULL; - - for (entry = l_queue_get_entries(certs); entry; entry = entry->next) { - struct l_cert *cert = entry->data; - struct l_key *key = l_cert_get_pubkey(cert); - - if (!key) { - sprintf(error, "Can't get public key from certificate " - "%i / %i in certificate set", i, - l_queue_length(certs)); - goto cleanup; - } - - if (!l_keyring_link(ring, key)) { - l_key_free(key); - sprintf(error, "Can't link the public key from " - "certificate %i / %i to target keyring", - i, l_queue_length(certs)); - goto cleanup; - } - - l_key_free_norevoke(key); - i++; - } - - return ring; - -cleanup: - l_keyring_free(ring); - return NULL; -} - -static bool cert_is_in_set(struct l_cert *cert, struct l_queue *set) -{ - const struct l_queue_entry *entry; - - for (entry = l_queue_get_entries(set); entry; entry = entry->next) { - struct l_cert *cert2 = entry->data; - - if (cert == cert2) - return true; - - if (cert->asn1_len == cert2->asn1_len && - !memcmp(cert->asn1, cert2->asn1, - cert->asn1_len)) - return true; - } - - return false; -} - -static struct l_key *cert_try_link(struct l_cert *cert, struct l_keyring *ring) -{ - struct l_key *key; - - key = l_key_new(L_KEY_RSA, cert->asn1, cert->asn1_len); - if (!key) - return NULL; - - if (l_keyring_link(ring, key)) - return key; - - l_key_free(key); - return NULL; -} - -static void cert_keyring_cleanup(struct l_keyring **p) -{ - l_keyring_free(*p); -} - -#define RETURN_ERROR(msg, args...) \ - do { \ - if (error) { \ - *error = error_buf; \ - snprintf(error_buf, sizeof(error_buf), msg, ## args); \ - } \ - return false; \ - } while (0) - -LIB_EXPORT bool l_certchain_verify(struct l_certchain *chain, - struct l_queue *ca_certs, - const char **error) -{ - struct l_keyring *ca_ring = NULL; - L_AUTO_CLEANUP_VAR(struct l_keyring *, verify_ring, - cert_keyring_cleanup) = NULL; - struct l_cert *cert; - struct l_key *prev_key = NULL; - int verified = 0; - static char error_buf[200]; - - if (unlikely(!chain || !chain->leaf)) - RETURN_ERROR("Chain empty"); - - verify_ring = l_keyring_new(); - if (!verify_ring) - RETURN_ERROR("Can't create verify keyring"); - - cert = chain->ca; - - /* - * For TLS compatibility the trusted root CA certificate is - * optionally present in the chain. - * - * RFC5246 7.4.2: - * "Because certificate validation requires that root keys be - * distributed independently, the self-signed certificate that - * specifies the root certificate authority MAY be omitted from - * the chain, under the assumption that the remote end must - * already possess it in order to validate it in any case." - * - * The following is an optimization to skip verifying the root - * cert in the chain if it is identical to one of the trusted CA - * certificates. It also happens to work around a kernel issue - * preventing self-signed certificates missing the AKID - * extension from being linked to a keyring. - */ - if (cert_is_in_set(cert, ca_certs)) { - verified++; - cert = cert->issued; - if (!cert) - return true; - - prev_key = cert_try_link(cert, verify_ring); - } else if (ca_certs) { - ca_ring = cert_set_to_keyring(ca_certs, error_buf); - if (!ca_ring) { - if (error) - *error = error_buf; - return false; - } - - if (!l_keyring_link_nested(verify_ring, ca_ring)) { - l_keyring_free(ca_ring); - RETURN_ERROR("Can't link CA ring to verify ring"); - } - } else - prev_key = cert_try_link(cert, verify_ring); - - /* - * The top, unverified certificate(s) are linked to the keyring and - * we can now force verification of any new certificates linked. - */ - if (!l_keyring_restrict(verify_ring, L_KEYRING_RESTRICT_ASYM_CHAIN, - NULL)) { - l_key_free(prev_key); - l_keyring_free(ca_ring); - RETURN_ERROR("Can't restrict verify keyring"); - } - - if (ca_ring) { - /* - * Verify the first certificate outside of the loop, then - * revoke the trusted CAs' keys so that only the newly - * verified cert's public key remains in the ring. - */ - prev_key = cert_try_link(cert, verify_ring); - l_keyring_free(ca_ring); - } - - cert = cert->issued; - - /* Verify the rest of the chain */ - while (prev_key && cert) { - struct l_key *new_key = cert_try_link(cert, verify_ring); - - /* - * Free and revoke the issuer's public key again leaving only - * new_key in verify_ring to ensure the next certificate linked - * is signed by the owner of this key. - */ - l_key_free(prev_key); - prev_key = new_key; - cert = cert->issued; - verified++; - } - - if (!prev_key) { - int total = 0; - - for (cert = chain->ca; cert; cert = cert->issued, total++); - RETURN_ERROR("Linking certificate %i / %i failed, root %s" - "verified against trusted CA(s) and the " - "following %i top certificates verified ok", - verified + 1, total, - ca_certs && verified ? "" : "not ", - verified ? verified - 1 : 0); - } - - l_key_free(prev_key); - return true; -} diff --git a/ell/cert.h b/ell/cert.h deleted file mode 100644 index 9fab88e..0000000 --- a/ell/cert.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_CERT_H -#define __ELL_CERT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -struct l_queue; -struct l_cert; -struct l_certchain; - -enum l_cert_key_type { - L_CERT_KEY_RSA, - L_CERT_KEY_UNKNOWN, -}; - -typedef bool (*l_cert_walk_cb_t)(struct l_cert *cert, void *user_data); - -struct l_cert *l_cert_new_from_der(const uint8_t *buf, size_t buf_len); -void l_cert_free(struct l_cert *cert); - -const uint8_t *l_cert_get_der_data(struct l_cert *cert, size_t *out_len); -const uint8_t *l_cert_get_dn(struct l_cert *cert, size_t *out_len); -enum l_cert_key_type l_cert_get_pubkey_type(struct l_cert *cert); -struct l_key *l_cert_get_pubkey(struct l_cert *cert); - -void l_certchain_free(struct l_certchain *chain); - -struct l_cert *l_certchain_get_leaf(struct l_certchain *chain); -void l_certchain_walk_from_leaf(struct l_certchain *chain, - l_cert_walk_cb_t cb, void *user_data); -void l_certchain_walk_from_ca(struct l_certchain *chain, - l_cert_walk_cb_t cb, void *user_data); - -bool l_certchain_verify(struct l_certchain *chain, struct l_queue *ca_certs, - const char **error); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_CERT_H */ diff --git a/ell/checksum.c b/ell/checksum.c deleted file mode 100644 index c33755c..0000000 --- a/ell/checksum.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include - -#include "util.h" -#include "checksum.h" -#include "private.h" - -#ifndef HAVE_LINUX_IF_ALG_H -#ifndef HAVE_LINUX_TYPES_H -typedef uint8_t __u8; -typedef uint16_t __u16; -typedef uint32_t __u32; -#else -#include -#endif - -#ifndef AF_ALG -#define AF_ALG 38 -#define PF_ALG AF_ALG -#endif - -struct sockaddr_alg { - __u16 salg_family; - __u8 salg_type[14]; - __u32 salg_feat; - __u32 salg_mask; - __u8 salg_name[64]; -}; - -/* Socket options */ -#define ALG_SET_KEY 1 - -#else -#include -#endif - -#ifndef SOL_ALG -#define SOL_ALG 279 -#endif - -struct checksum_info { - const char *name; - uint8_t digest_len; - bool supported; -}; - -static struct checksum_info checksum_algs[] = { - [L_CHECKSUM_MD4] = { .name = "md4", .digest_len = 16 }, - [L_CHECKSUM_MD5] = { .name = "md5", .digest_len = 16 }, - [L_CHECKSUM_SHA1] = { .name = "sha1", .digest_len = 20 }, - [L_CHECKSUM_SHA256] = { .name = "sha256", .digest_len = 32 }, - [L_CHECKSUM_SHA384] = { .name = "sha384", .digest_len = 48 }, - [L_CHECKSUM_SHA512] = { .name = "sha512", .digest_len = 64 }, -}; - -static struct checksum_info checksum_cmac_aes_alg = - { .name = "cmac(aes)", .digest_len = 16 }; - -static struct checksum_info checksum_hmac_algs[] = { - [L_CHECKSUM_MD4] = { .name = "hmac(md4)", .digest_len = 16 }, - [L_CHECKSUM_MD5] = { .name = "hmac(md5)", .digest_len = 16 }, - [L_CHECKSUM_SHA1] = { .name = "hmac(sha1)", .digest_len = 20 }, - [L_CHECKSUM_SHA256] = { .name = "hmac(sha256)", .digest_len = 32 }, - [L_CHECKSUM_SHA384] = { .name = "hmac(sha384)", .digest_len = 48 }, - [L_CHECKSUM_SHA512] = { .name = "hmac(sha512)", .digest_len = 64 }, -}; - -static const struct { - struct checksum_info *list; - size_t n; -} checksum_info_table[] = { - { checksum_algs, L_ARRAY_SIZE(checksum_algs) }, - { &checksum_cmac_aes_alg, 1 }, - { checksum_hmac_algs, L_ARRAY_SIZE(checksum_hmac_algs) }, - {} -}; - -/** - * SECTION:checksum - * @short_description: Checksum handling - * - * Checksum handling - */ - -#define is_valid_index(array, i) ((i) >= 0 && (i) < L_ARRAY_SIZE(array)) - -/** - * l_checksum: - * - * Opaque object representing the checksum. - */ -struct l_checksum { - int sk; - const struct checksum_info *alg_info; -}; - -static int create_alg(const char *alg) -{ - struct sockaddr_alg salg; - int sk; - - sk = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); - if (sk < 0) - return -1; - - memset(&salg, 0, sizeof(salg)); - salg.salg_family = AF_ALG; - strcpy((char *) salg.salg_type, "hash"); - strcpy((char *) salg.salg_name, alg); - - if (bind(sk, (struct sockaddr *) &salg, sizeof(salg)) < 0) { - close(sk); - return -1; - } - - return sk; -} - -/** - * l_checksum_new: - * @type: checksum type - * - * Creates new #l_checksum, using the checksum algorithm @type. - * - * Returns: a newly allocated #l_checksum object. - **/ -LIB_EXPORT struct l_checksum *l_checksum_new(enum l_checksum_type type) -{ - struct l_checksum *checksum; - int fd; - - if (!is_valid_index(checksum_algs, type) || !checksum_algs[type].name) - return NULL; - - checksum = l_new(struct l_checksum, 1); - checksum->alg_info = &checksum_algs[type]; - - fd = create_alg(checksum->alg_info->name); - if (fd < 0) - goto error; - - checksum->sk = accept4(fd, NULL, 0, SOCK_CLOEXEC); - close(fd); - - if (checksum->sk < 0) - goto error; - - return checksum; - -error: - l_free(checksum); - return NULL; -} - -LIB_EXPORT struct l_checksum *l_checksum_new_cmac_aes(const void *key, - size_t key_len) -{ - struct l_checksum *checksum; - int fd; - - fd = create_alg("cmac(aes)"); - if (fd < 0) - return NULL; - - if (setsockopt(fd, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) { - close(fd); - return NULL; - } - - checksum = l_new(struct l_checksum, 1); - checksum->sk = accept4(fd, NULL, 0, SOCK_CLOEXEC); - close(fd); - - if (checksum->sk < 0) { - l_free(checksum); - return NULL; - } - - checksum->alg_info = &checksum_cmac_aes_alg; - return checksum; -} - -LIB_EXPORT struct l_checksum *l_checksum_new_hmac(enum l_checksum_type type, - const void *key, size_t key_len) -{ - struct l_checksum *checksum; - int fd; - - if (!is_valid_index(checksum_hmac_algs, type) || - !checksum_hmac_algs[type].name) - return NULL; - - fd = create_alg(checksum_hmac_algs[type].name); - if (fd < 0) - return NULL; - - if (setsockopt(fd, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) { - close(fd); - return NULL; - } - - checksum = l_new(struct l_checksum, 1); - checksum->sk = accept4(fd, NULL, 0, SOCK_CLOEXEC); - close(fd); - - if (checksum->sk < 0) { - l_free(checksum); - return NULL; - } - - checksum->alg_info = &checksum_hmac_algs[type]; - return checksum; -} - -/** - * l_checksum_clone: - * @checksum: parent checksum object - * - * Creates a new checksum with an independent copy of parent @checksum's - * state. l_checksum_get_digest can then be called on the parent or the - * clone without affecting the state of the other object. - **/ -LIB_EXPORT struct l_checksum *l_checksum_clone(struct l_checksum *checksum) -{ - struct l_checksum *clone; - - if (unlikely(!checksum)) - return NULL; - - clone = l_new(struct l_checksum, 1); - clone->sk = accept4(checksum->sk, NULL, 0, SOCK_CLOEXEC); - - if (clone->sk < 0) { - l_free(clone); - return NULL; - } - - clone->alg_info = checksum->alg_info; - return clone; -} - -/** - * l_checksum_free: - * @checksum: checksum object - * - * Frees the memory allocated for @checksum. - **/ -LIB_EXPORT void l_checksum_free(struct l_checksum *checksum) -{ - if (unlikely(!checksum)) - return; - - close(checksum->sk); - l_free(checksum); -} - -/** - * l_checksum_reset: - * @checksum: checksum object - * - * Resets the internal state of @checksum. - **/ -LIB_EXPORT void l_checksum_reset(struct l_checksum *checksum) -{ - if (unlikely(!checksum)) - return; - - send(checksum->sk, NULL, 0, 0); -} - -/** - * l_checksum_update: - * @checksum: checksum object - * @data: data pointer - * @len: length of data - * - * Updates checksum from @data pointer with @len bytes. - * - * Returns: true if the operation succeeded, false otherwise. - **/ -LIB_EXPORT bool l_checksum_update(struct l_checksum *checksum, - const void *data, size_t len) -{ - ssize_t written; - - if (unlikely(!checksum)) - return false; - - written = send(checksum->sk, data, len, MSG_MORE); - if (written < 0) - return false; - - return true; -} - -/** - * l_checksum_updatev: - * @checksum: checksum object - * @iov: iovec pointer - * @iov_len: Number of iovec entries - * - * This is a iovec based version of l_checksum_update; it updates the checksum - * based on contents of @iov and @iov_len. - * - * Returns: true if the operation succeeded, false otherwise. - **/ -LIB_EXPORT bool l_checksum_updatev(struct l_checksum *checksum, - const struct iovec *iov, size_t iov_len) -{ - struct msghdr msg; - ssize_t written; - - if (unlikely(!checksum)) - return false; - - if (unlikely(!iov) || unlikely(!iov_len)) - return false; - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = (struct iovec *) iov; - msg.msg_iovlen = iov_len; - - written = sendmsg(checksum->sk, &msg, MSG_MORE); - if (written < 0) - return false; - - return true; -} - -/** - * l_checksum_get_digest: - * @checksum: checksum object - * @digest: output data buffer - * @len: length of output buffer - * - * Writes the digest from @checksum as raw binary data into the provided - * buffer or, if the buffer is shorter, the initial @len bytes of the digest - * data. - * - * Returns: Number of bytes written, or negative value if an error occurred. - **/ -LIB_EXPORT ssize_t l_checksum_get_digest(struct l_checksum *checksum, - void *digest, size_t len) -{ - ssize_t result; - - if (unlikely(!checksum)) - return -EINVAL; - - if (unlikely(!digest)) - return -EFAULT; - - if (unlikely(!len)) - return -EINVAL; - - result = recv(checksum->sk, digest, len, 0); - if (result < 0) - return -errno; - - if ((size_t) result < len && result < checksum->alg_info->digest_len) - return -EIO; - - return result; -} - -/** - * l_checksum_get_string: - * @checksum: checksum object - * - * Gets the digest from @checksum as hex encoded string. - * - * Returns: a newly allocated hex string - **/ -LIB_EXPORT char *l_checksum_get_string(struct l_checksum *checksum) -{ - unsigned char digest[64]; - - if (unlikely(!checksum)) - return NULL; - - l_checksum_get_digest(checksum, digest, sizeof(digest)); - - return l_util_hexstring(digest, checksum->alg_info->digest_len); -} - -static void init_supported() -{ - static bool initialized = false; - struct sockaddr_alg salg; - int sk; - unsigned int i, j; - - if (likely(initialized)) - return; - - initialized = true; - - sk = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); - if (sk < 0) - return; - - memset(&salg, 0, sizeof(salg)); - salg.salg_family = AF_ALG; - strcpy((char *) salg.salg_type, "hash"); - - for (i = 0; checksum_info_table[i].list; i++) - for (j = 0; j < checksum_info_table[i].n; j++) { - struct checksum_info *info; - - info = &checksum_info_table[i].list[j]; - if (!info->name) - continue; - - strcpy((char *) salg.salg_name, info->name); - - if (bind(sk, (struct sockaddr *) &salg, - sizeof(salg)) < 0) - continue; - - info->supported = true; - } - - close(sk); -} - -LIB_EXPORT bool l_checksum_is_supported(enum l_checksum_type type, - bool check_hmac) -{ - const struct checksum_info *list; - - init_supported(); - - if (!check_hmac) { - if (!is_valid_index(checksum_algs, type)) - return false; - - list = checksum_algs; - } else { - if (!is_valid_index(checksum_hmac_algs, type)) - return false; - - list = checksum_hmac_algs; - } - - return list[type].supported; -} - -LIB_EXPORT bool l_checksum_cmac_aes_supported() -{ - init_supported(); - - return checksum_cmac_aes_alg.supported; -} - -LIB_EXPORT ssize_t l_checksum_digest_length(enum l_checksum_type type) -{ - return is_valid_index(checksum_algs, type) ? - checksum_algs[type].digest_len : 0; -} diff --git a/ell/checksum.h b/ell/checksum.h deleted file mode 100644 index 08d74b7..0000000 --- a/ell/checksum.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_CHECKSUM_H -#define __ELL_CHECKSUM_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_checksum; - -enum l_checksum_type { - L_CHECKSUM_NONE, - L_CHECKSUM_MD4, - L_CHECKSUM_MD5, - L_CHECKSUM_SHA1, - L_CHECKSUM_SHA224, - L_CHECKSUM_SHA256, - L_CHECKSUM_SHA384, - L_CHECKSUM_SHA512, -}; - -struct l_checksum *l_checksum_new(enum l_checksum_type type); -struct l_checksum *l_checksum_new_cmac_aes(const void *key, size_t key_len); -struct l_checksum *l_checksum_new_hmac(enum l_checksum_type type, - const void *key, size_t key_len); -struct l_checksum *l_checksum_clone(struct l_checksum *checksum); - -void l_checksum_free(struct l_checksum *checksum); - -void l_checksum_reset(struct l_checksum *checksum); - -bool l_checksum_update(struct l_checksum *checksum, - const void *data, size_t len); -bool l_checksum_updatev(struct l_checksum *checksum, - const struct iovec *iov, - size_t iov_len); -ssize_t l_checksum_get_digest(struct l_checksum *checksum, - void *digest, size_t len); -char *l_checksum_get_string(struct l_checksum *checksum); - -bool l_checksum_is_supported(enum l_checksum_type type, bool check_hmac); -bool l_checksum_cmac_aes_supported(); - -ssize_t l_checksum_digest_length(enum l_checksum_type type); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_CHECKSUM_H */ diff --git a/ell/cipher.c b/ell/cipher.c deleted file mode 100644 index 27600da..0000000 --- a/ell/cipher.c +++ /dev/null @@ -1,664 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2015 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include - -#include "util.h" -#include "cipher.h" -#include "private.h" -#include "random.h" - -#ifndef HAVE_LINUX_IF_ALG_H -#ifndef HAVE_LINUX_TYPES_H -typedef uint8_t __u8; -typedef uint16_t __u16; -typedef uint32_t __u32; -#else -#include -#endif - -#ifndef AF_ALG -#define AF_ALG 38 -#define PF_ALG AF_ALG -#endif - -struct sockaddr_alg { - __u16 salg_family; - __u8 salg_type[14]; - __u32 salg_feat; - __u32 salg_mask; - __u8 salg_name[64]; -}; - -struct af_alg_iv { - __u32 ivlen; - __u8 iv[0]; -}; - -/* Socket options */ -#define ALG_SET_KEY 1 -#define ALG_SET_IV 2 -#define ALG_SET_OP 3 - -/* Operations */ -#define ALG_OP_DECRYPT 0 -#define ALG_OP_ENCRYPT 1 -#else -#include -#endif - -#ifndef SOL_ALG -#define SOL_ALG 279 -#endif - -#ifndef ALG_SET_AEAD_ASSOCLEN -#define ALG_SET_AEAD_ASSOCLEN 4 -#endif - -#ifndef ALG_SET_AEAD_AUTHSIZE -#define ALG_SET_AEAD_AUTHSIZE 5 -#endif - -#define is_valid_type(type) ((type) <= L_CIPHER_DES3_EDE_CBC) - -static uint32_t supported_ciphers; -static uint32_t supported_aead_ciphers; - -struct l_cipher { - int type; - int encrypt_sk; - int decrypt_sk; -}; - -struct l_aead_cipher { - int type; - int sk; -}; - -static int create_alg(const char *alg_type, const char *alg_name, - const void *key, size_t key_length, size_t tag_length) -{ - struct sockaddr_alg salg; - int sk; - int ret; - - sk = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); - if (sk < 0) - return -errno; - - memset(&salg, 0, sizeof(salg)); - salg.salg_family = AF_ALG; - strcpy((char *) salg.salg_type, alg_type); - strcpy((char *) salg.salg_name, alg_name); - - if (bind(sk, (struct sockaddr *) &salg, sizeof(salg)) < 0) { - close(sk); - return -1; - } - - if (setsockopt(sk, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) { - close(sk); - return -1; - } - - if (tag_length && setsockopt(sk, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, - tag_length)) { - close(sk); - return -1; - } - - ret = accept4(sk, NULL, 0, SOCK_CLOEXEC); - close(sk); - - return ret; -} - -static const char *cipher_type_to_name(enum l_cipher_type type) -{ - switch (type) { - case L_CIPHER_AES: - return "ecb(aes)"; - case L_CIPHER_AES_CBC: - return "cbc(aes)"; - case L_CIPHER_AES_CTR: - return "ctr(aes)"; - case L_CIPHER_ARC4: - return "ecb(arc4)"; - case L_CIPHER_DES: - return "ecb(des)"; - case L_CIPHER_DES_CBC: - return "cbc(des)"; - case L_CIPHER_DES3_EDE_CBC: - return "cbc(des3_ede)"; - } - - return NULL; -} - -LIB_EXPORT struct l_cipher *l_cipher_new(enum l_cipher_type type, - const void *key, - size_t key_length) -{ - struct l_cipher *cipher; - const char *uninitialized_var(alg_name); - - if (unlikely(!key)) - return NULL; - - if (!is_valid_type(type)) - return NULL; - - cipher = l_new(struct l_cipher, 1); - cipher->type = type; - alg_name = cipher_type_to_name(type); - - cipher->encrypt_sk = create_alg("skcipher", alg_name, key, key_length, - 0); - if (cipher->encrypt_sk < 0) - goto error_free; - - cipher->decrypt_sk = create_alg("skcipher", alg_name, key, key_length, - 0); - if (cipher->decrypt_sk < 0) - goto error_close; - - return cipher; - -error_close: - close(cipher->encrypt_sk); -error_free: - l_free(cipher); - return NULL; -} - -static const char *aead_cipher_type_to_name(enum l_aead_cipher_type type) -{ - switch (type) { - case L_AEAD_CIPHER_AES_CCM: - return "ccm(aes)"; - case L_AEAD_CIPHER_AES_GCM: - return "gcm(aes)"; - } - - return NULL; -} - -LIB_EXPORT struct l_aead_cipher *l_aead_cipher_new(enum l_aead_cipher_type type, - const void *key, - size_t key_length, - size_t tag_length) -{ - struct l_aead_cipher *cipher; - const char *alg_name; - - if (unlikely(!key)) - return NULL; - - if (type != L_AEAD_CIPHER_AES_CCM && type != L_AEAD_CIPHER_AES_GCM) - return NULL; - - cipher = l_new(struct l_aead_cipher, 1); - cipher->type = type; - alg_name = aead_cipher_type_to_name(type); - - cipher->sk = create_alg("aead", alg_name, key, key_length, tag_length); - if (cipher->sk >= 0) - return cipher; - - l_free(cipher); - return NULL; -} - -LIB_EXPORT void l_cipher_free(struct l_cipher *cipher) -{ - if (unlikely(!cipher)) - return; - - close(cipher->encrypt_sk); - close(cipher->decrypt_sk); - - l_free(cipher); -} - -LIB_EXPORT void l_aead_cipher_free(struct l_aead_cipher *cipher) -{ - if (unlikely(!cipher)) - return; - - close(cipher->sk); - - l_free(cipher); -} - -static ssize_t operate_cipher(int sk, __u32 operation, - const void *in, size_t in_len, - const void *ad, size_t ad_len, - const void *iv, size_t iv_len, - void *out, size_t out_len) -{ - char *c_msg_buf; - size_t c_msg_size; - struct msghdr msg; - struct cmsghdr *c_msg; - struct iovec iov[2]; - ssize_t result; - - c_msg_size = CMSG_SPACE(sizeof(operation)); - c_msg_size += ad_len ? CMSG_SPACE(sizeof(uint32_t)) : 0; - c_msg_size += iv_len ? - CMSG_SPACE(sizeof(struct af_alg_iv) + iv_len) : 0; - - c_msg_buf = alloca(c_msg_size); - - memset(c_msg_buf, 0, c_msg_size); - memset(&msg, 0, sizeof(msg)); - - msg.msg_iov = iov; - - msg.msg_control = c_msg_buf; - msg.msg_controllen = c_msg_size; - - c_msg = CMSG_FIRSTHDR(&msg); - c_msg->cmsg_level = SOL_ALG; - c_msg->cmsg_type = ALG_SET_OP; - c_msg->cmsg_len = CMSG_LEN(sizeof(operation)); - memcpy(CMSG_DATA(c_msg), &operation, sizeof(operation)); - - if (ad_len) { - uint32_t *ad_data; - - c_msg = CMSG_NXTHDR(&msg, c_msg); - c_msg->cmsg_level = SOL_ALG; - c_msg->cmsg_type = ALG_SET_AEAD_ASSOCLEN; - c_msg->cmsg_len = CMSG_LEN(sizeof(*ad_data)); - ad_data = (void *) CMSG_DATA(c_msg); - *ad_data = ad_len; - - iov[0].iov_base = (void *) ad; - iov[0].iov_len = ad_len; - iov[1].iov_base = (void *) in; - iov[1].iov_len = in_len; - msg.msg_iovlen = 2; - } else { - iov[0].iov_base = (void *) in; - iov[0].iov_len = in_len; - msg.msg_iovlen = 1; - } - - if (iv_len) { - struct af_alg_iv *algiv; - - c_msg = CMSG_NXTHDR(&msg, c_msg); - c_msg->cmsg_level = SOL_ALG; - c_msg->cmsg_type = ALG_SET_IV; - c_msg->cmsg_len = CMSG_LEN(sizeof(*algiv) + iv_len); - - algiv = (void *)CMSG_DATA(c_msg); - algiv->ivlen = iv_len; - memcpy(algiv->iv, iv, iv_len); - } - - result = sendmsg(sk, &msg, 0); - if (result < 0) - return -errno; - - if (ad_len) { - /* - * When AEAD additional data is passed to sendmsg() for - * use in computing the tag, those bytes also appear at - * the beginning of the encrypt or decrypt results. Rather - * than force the caller to pad their result buffer with - * the correct number of bytes for the additional data, - * the necessary space is allocated here and then the - * duplicate AAD is discarded. - */ - iov[0].iov_base = l_malloc(ad_len); - iov[0].iov_len = ad_len; - iov[1].iov_base = (void *) out; - iov[1].iov_len = out_len; - msg.msg_iovlen = 2; - - msg.msg_control = NULL; - msg.msg_controllen = 0; - - result = recvmsg(sk, &msg, 0); - - if (result >= (ssize_t) ad_len) - result -= ad_len; - else if (result > 0) - result = 0; - - l_free(iov[0].iov_base); - } else { - result = read(sk, out, out_len); - } - - if (result < 0) - return -errno; - - return result; -} - -static ssize_t operate_cipherv(int sk, __u32 operation, - const struct iovec *in, size_t in_cnt, - const struct iovec *out, size_t out_cnt) -{ - char *c_msg_buf; - size_t c_msg_size; - struct msghdr msg; - struct cmsghdr *c_msg; - ssize_t result; - - c_msg_size = CMSG_SPACE(sizeof(operation)); - c_msg_buf = alloca(c_msg_size); - - memset(c_msg_buf, 0, c_msg_size); - memset(&msg, 0, sizeof(msg)); - - msg.msg_iov = (struct iovec *) in; - msg.msg_iovlen = in_cnt; - - msg.msg_control = c_msg_buf; - msg.msg_controllen = c_msg_size; - - c_msg = CMSG_FIRSTHDR(&msg); - c_msg->cmsg_level = SOL_ALG; - c_msg->cmsg_type = ALG_SET_OP; - c_msg->cmsg_len = CMSG_LEN(sizeof(operation)); - memcpy(CMSG_DATA(c_msg), &operation, sizeof(operation)); - - result = sendmsg(sk, &msg, 0); - if (result < 0) - return -errno; - - result = readv(sk, out, out_cnt); - - if (result < 0) - return -errno; - - return result; -} - -LIB_EXPORT bool l_cipher_encrypt(struct l_cipher *cipher, - const void *in, void *out, size_t len) -{ - if (unlikely(!cipher)) - return false; - - if (unlikely(!in) || unlikely(!out)) - return false; - - return operate_cipher(cipher->encrypt_sk, ALG_OP_ENCRYPT, in, len, - NULL, 0, NULL, 0, out, len) >= 0; -} - -LIB_EXPORT bool l_cipher_encryptv(struct l_cipher *cipher, - const struct iovec *in, size_t in_cnt, - const struct iovec *out, size_t out_cnt) -{ - if (unlikely(!cipher)) - return false; - - if (unlikely(!in) || unlikely(!out)) - return false; - - return operate_cipherv(cipher->encrypt_sk, ALG_OP_ENCRYPT, in, in_cnt, - out, out_cnt) >= 0; -} - -LIB_EXPORT bool l_cipher_decrypt(struct l_cipher *cipher, - const void *in, void *out, size_t len) -{ - if (unlikely(!cipher)) - return false; - - if (unlikely(!in) || unlikely(!out)) - return false; - - return operate_cipher(cipher->decrypt_sk, ALG_OP_DECRYPT, in, len, - NULL, 0, NULL, 0, out, len) >= 0; -} - -LIB_EXPORT bool l_cipher_decryptv(struct l_cipher *cipher, - const struct iovec *in, size_t in_cnt, - const struct iovec *out, size_t out_cnt) -{ - if (unlikely(!cipher)) - return false; - - if (unlikely(!in) || unlikely(!out)) - return false; - - return operate_cipherv(cipher->decrypt_sk, ALG_OP_DECRYPT, in, in_cnt, - out, out_cnt) >= 0; -} - -LIB_EXPORT bool l_cipher_set_iv(struct l_cipher *cipher, const uint8_t *iv, - size_t iv_length) -{ - char c_msg_buf[CMSG_SPACE(4 + iv_length)]; - struct msghdr msg; - struct cmsghdr *c_msg; - uint32_t len = iv_length; - - if (unlikely(!cipher)) - return false; - - memset(&c_msg_buf, 0, sizeof(c_msg_buf)); - memset(&msg, 0, sizeof(struct msghdr)); - - msg.msg_control = c_msg_buf; - msg.msg_controllen = sizeof(c_msg_buf); - - c_msg = CMSG_FIRSTHDR(&msg); - c_msg->cmsg_level = SOL_ALG; - c_msg->cmsg_type = ALG_SET_IV; - c_msg->cmsg_len = CMSG_LEN(4 + iv_length); - memcpy(CMSG_DATA(c_msg) + 0, &len, 4); - memcpy(CMSG_DATA(c_msg) + 4, iv, iv_length); - - msg.msg_iov = NULL; - msg.msg_iovlen = 0; - - if (sendmsg(cipher->encrypt_sk, &msg, 0) < 0) - return false; - - if (sendmsg(cipher->decrypt_sk, &msg, 0) < 0) - return false; - - return true; -} - -#define CCM_IV_SIZE 16 - -static size_t l_aead_cipher_get_ivlen(struct l_aead_cipher *cipher) -{ - switch (cipher->type) { - case L_AEAD_CIPHER_AES_CCM: - return CCM_IV_SIZE; - case L_AEAD_CIPHER_AES_GCM: - return 12; - } - - return 0; -} - -/* RFC3610 Section 2.3 */ -static ssize_t build_ccm_iv(const void *nonce, uint8_t nonce_len, - uint8_t (*iv)[CCM_IV_SIZE]) -{ - const size_t iv_overhead = 2; - int lprime = 15 - nonce_len - 1; - - if (unlikely(nonce_len + iv_overhead > CCM_IV_SIZE || lprime > 7)) - return -EINVAL; - - (*iv)[0] = lprime; - memcpy(*iv + 1, nonce, nonce_len); - memset(*iv + 1 + nonce_len, 0, lprime + 1); - - return CCM_IV_SIZE; -} - -LIB_EXPORT bool l_aead_cipher_encrypt(struct l_aead_cipher *cipher, - const void *in, size_t in_len, - const void *ad, size_t ad_len, - const void *nonce, size_t nonce_len, - void *out, size_t out_len) -{ - uint8_t ccm_iv[CCM_IV_SIZE]; - const uint8_t *iv; - ssize_t iv_len; - - if (unlikely(!cipher)) - return false; - - if (unlikely(!in) || unlikely(!out)) - return false; - - if (cipher->type == L_AEAD_CIPHER_AES_CCM) { - iv_len = build_ccm_iv(nonce, nonce_len, &ccm_iv); - if (unlikely(iv_len < 0)) - return false; - - iv = ccm_iv; - } else { - if (unlikely(nonce_len != l_aead_cipher_get_ivlen(cipher))) - return false; - - iv = nonce; - iv_len = nonce_len; - } - - return operate_cipher(cipher->sk, ALG_OP_ENCRYPT, in, in_len, - ad, ad_len, iv, iv_len, out, out_len) == - (ssize_t)out_len; -} - -LIB_EXPORT bool l_aead_cipher_decrypt(struct l_aead_cipher *cipher, - const void *in, size_t in_len, - const void *ad, size_t ad_len, - const void *nonce, size_t nonce_len, - void *out, size_t out_len) -{ - uint8_t ccm_iv[CCM_IV_SIZE]; - const uint8_t *iv; - ssize_t iv_len; - - if (unlikely(!cipher)) - return false; - - if (unlikely(!in) || unlikely(!out)) - return false; - - if (cipher->type == L_AEAD_CIPHER_AES_CCM) { - iv_len = build_ccm_iv(nonce, nonce_len, &ccm_iv); - if (unlikely(iv_len < 0)) - return false; - - iv = ccm_iv; - } else { - if (unlikely(nonce_len != l_aead_cipher_get_ivlen(cipher))) - return false; - - iv = nonce; - iv_len = nonce_len; - } - - return operate_cipher(cipher->sk, ALG_OP_DECRYPT, in, in_len, - ad, ad_len, iv, iv_len, out, out_len) == - (ssize_t)out_len; -} - -static void init_supported() -{ - static bool initialized = false; - struct sockaddr_alg salg; - int sk; - enum l_cipher_type c; - enum l_aead_cipher_type a; - - if (likely(initialized)) - return; - - initialized = true; - - sk = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); - if (sk < 0) - return; - - memset(&salg, 0, sizeof(salg)); - salg.salg_family = AF_ALG; - strcpy((char *) salg.salg_type, "skcipher"); - - for (c = L_CIPHER_AES; c <= L_CIPHER_DES3_EDE_CBC; c++) { - strcpy((char *) salg.salg_name, cipher_type_to_name(c)); - - if (bind(sk, (struct sockaddr *) &salg, sizeof(salg)) < 0) - continue; - - supported_ciphers |= 1 << c; - } - - strcpy((char *) salg.salg_type, "aead"); - - for (a = L_AEAD_CIPHER_AES_CCM; a <= L_AEAD_CIPHER_AES_GCM; a++) { - strcpy((char *) salg.salg_name, aead_cipher_type_to_name(a)); - - if (bind(sk, (struct sockaddr *) &salg, sizeof(salg)) < 0) - continue; - - supported_aead_ciphers |= 1 << a; - } - - close(sk); -} - -LIB_EXPORT bool l_cipher_is_supported(enum l_cipher_type type) -{ - if (!is_valid_type(type)) - return false; - - init_supported(); - - return supported_ciphers & (1 << type); -} - -LIB_EXPORT bool l_aead_cipher_is_supported(enum l_aead_cipher_type type) -{ - if (type != L_AEAD_CIPHER_AES_CCM && type != L_AEAD_CIPHER_AES_GCM) - return false; - - init_supported(); - - return supported_aead_ciphers & (1 << type); -} diff --git a/ell/cipher.h b/ell/cipher.h deleted file mode 100644 index 84f2988..0000000 --- a/ell/cipher.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2015 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_CIPHER_H -#define __ELL_CIPHER_H - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_cipher; - -enum l_cipher_type { - L_CIPHER_AES = 0, - L_CIPHER_AES_CBC, - L_CIPHER_AES_CTR, - L_CIPHER_ARC4, - L_CIPHER_DES, - L_CIPHER_DES_CBC, - L_CIPHER_DES3_EDE_CBC, -}; - -struct l_cipher *l_cipher_new(enum l_cipher_type type, - const void *key, size_t key_length); - -void l_cipher_free(struct l_cipher *cipher); - -bool l_cipher_encrypt(struct l_cipher *cipher, - const void *in, void *out, size_t len); -bool l_cipher_encryptv(struct l_cipher *cipher, - const struct iovec *in, size_t in_cnt, - const struct iovec *out, size_t out_cnt); - -bool l_cipher_decrypt(struct l_cipher *cipher, - const void *in, void *out, size_t len); -bool l_cipher_decryptv(struct l_cipher *cipher, - const struct iovec *in, size_t in_cnt, - const struct iovec *out, size_t out_cnt); - -bool l_cipher_set_iv(struct l_cipher *cipher, const uint8_t *iv, - size_t iv_length); - -struct l_aead_cipher; - -enum l_aead_cipher_type { - L_AEAD_CIPHER_AES_CCM = 0, - L_AEAD_CIPHER_AES_GCM, -}; - -struct l_aead_cipher *l_aead_cipher_new(enum l_aead_cipher_type type, - const void *key, size_t key_length, - size_t tag_length); - -void l_aead_cipher_free(struct l_aead_cipher *cipher); - -bool l_aead_cipher_encrypt(struct l_aead_cipher *cipher, - const void *in, size_t in_len, - const void *ad, size_t ad_len, - const void *nonce, size_t nonce_len, - void *out, size_t out_len); - -bool l_aead_cipher_decrypt(struct l_aead_cipher *cipher, - const void *in, size_t in_len, - const void *ad, size_t ad_len, - const void *nonce, size_t nonce_len, - void *out, size_t out_len); - -bool l_cipher_is_supported(enum l_cipher_type type); -bool l_aead_cipher_is_supported(enum l_aead_cipher_type type); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_CIPHER_H */ diff --git a/ell/dbus-client.c b/ell/dbus-client.c deleted file mode 100644 index 541f3e8..0000000 --- a/ell/dbus-client.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * Copyright (C) 2017 Codecoup. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "dbus.h" -#include "dbus-client.h" -#include "queue.h" -#include "private.h" - -struct l_dbus_client { - struct l_dbus *dbus; - unsigned int watch; - unsigned int added_watch; - unsigned int removed_watch; - char *service; - uint32_t objects_call; - - l_dbus_watch_func_t connect_cb; - void *connect_cb_data; - l_dbus_destroy_func_t connect_cb_data_destroy; - - l_dbus_watch_func_t disconnect_cb; - void *disconnect_cb_data; - l_dbus_destroy_func_t disconnect_cb_data_destroy; - - l_dbus_client_ready_func_t ready_cb; - void *ready_cb_data; - l_dbus_destroy_func_t ready_cb_data_destroy; - - l_dbus_client_proxy_func_t proxy_added_cb; - l_dbus_client_proxy_func_t proxy_removed_cb; - l_dbus_client_property_function_t properties_changed_cb; - void *proxy_cb_data; - l_dbus_destroy_func_t proxy_cb_data_destroy; - - struct l_queue *proxies; -}; - -struct proxy_property { - char *name; - struct l_dbus_message *msg; -}; - -struct l_dbus_proxy { - struct l_dbus_client *client; - char *interface; - char *path; - uint32_t properties_watch; - bool ready; - - struct l_queue *properties; - struct l_queue *pending_calls; -}; - -LIB_EXPORT const char *l_dbus_proxy_get_path(struct l_dbus_proxy *proxy) -{ - if (unlikely(!proxy)) - return NULL; - - return proxy->path; -} - -LIB_EXPORT const char *l_dbus_proxy_get_interface(struct l_dbus_proxy *proxy) -{ - if (unlikely(!proxy)) - return NULL; - - return proxy->interface; -} - -static bool property_match_by_name(const void *a, const void *b) -{ - const struct proxy_property *prop = a; - const char *name = b; - - return !strcmp(prop->name, name); -} - -static struct proxy_property *find_property(struct l_dbus_proxy *proxy, - const char *name) -{ - return l_queue_find(proxy->properties, property_match_by_name, name); -} - -static struct proxy_property *get_property(struct l_dbus_proxy *proxy, - const char *name) -{ - struct proxy_property *prop; - - prop = find_property(proxy, name); - if (prop) - return prop; - - prop = l_new(struct proxy_property, 1); - prop->name = l_strdup(name); - - l_queue_push_tail(proxy->properties, prop); - - return prop; -} - -LIB_EXPORT bool l_dbus_proxy_get_property(struct l_dbus_proxy *proxy, - const char *name, - const char *signature, ...) -{ - struct proxy_property *prop; - va_list args; - bool res; - - if (unlikely(!proxy)) - return false; - - prop = find_property(proxy, name); - if (!prop) - return false; - - va_start(args, signature); - res = l_dbus_message_get_arguments_valist(prop->msg, signature, args); - va_end(args); - - return res; -} - -static void property_free(void *data) -{ - struct proxy_property *prop = data; - - if (prop->msg) - l_dbus_message_unref(prop->msg); - - l_free(prop->name); - l_free(prop); -} - -static void cancel_pending_calls(struct l_dbus_proxy *proxy) -{ - const struct l_queue_entry *entry; - - for (entry = l_queue_get_entries(proxy->pending_calls); entry; - entry = entry->next) { - uint32_t call_id = L_PTR_TO_UINT(entry->data); - - l_dbus_cancel(proxy->client->dbus, call_id); - } -} - -static void dbus_proxy_destroy(struct l_dbus_proxy *proxy) -{ - if (unlikely(!proxy)) - return; - - if (proxy->properties_watch) - l_dbus_remove_signal_watch(proxy->client->dbus, - proxy->properties_watch); - - cancel_pending_calls(proxy); - l_queue_destroy(proxy->pending_calls, NULL); - l_queue_destroy(proxy->properties, property_free); - l_free(proxy->interface); - l_free(proxy->path); - l_free(proxy); -} - -struct method_call_request -{ - struct l_dbus_proxy *proxy; - uint32_t call_id; - l_dbus_message_func_t setup; - l_dbus_client_proxy_result_func_t result; - void *user_data; - l_dbus_destroy_func_t destroy; -}; - -static void method_call_request_free(void *user_data) -{ - struct method_call_request *req = user_data; - - l_queue_remove(req->proxy->pending_calls, L_UINT_TO_PTR(req->call_id)); - - if (req->destroy) - req->destroy(req->user_data); - - l_free(req); -} - -static void method_call_setup(struct l_dbus_message *message, void *user_data) -{ - struct method_call_request *req = user_data; - - if (req->setup) - req->setup(message, req->user_data); - else - l_dbus_message_set_arguments(message, ""); -} - -static void method_call_reply(struct l_dbus_message *message, void *user_data) -{ - struct method_call_request *req = user_data; - - if (req->result) - req->result(req->proxy, message, req->user_data); -} - -LIB_EXPORT bool l_dbus_proxy_set_property(struct l_dbus_proxy *proxy, - l_dbus_client_proxy_result_func_t result, - void *user_data, l_dbus_destroy_func_t destroy, - const char *name, const char *signature, ...) -{ - struct l_dbus_client *client = proxy->client; - struct l_dbus_message_builder *builder; - struct method_call_request *req; - struct l_dbus_message *message; - struct proxy_property *prop; - va_list args; - - if (unlikely(!proxy)) - return false; - - prop = find_property(proxy, name); - if (!prop) - return false; - - if (strcmp(l_dbus_message_get_signature(prop->msg), signature)) - return false; - - message = l_dbus_message_new_method_call(client->dbus, client->service, - proxy->path, - L_DBUS_INTERFACE_PROPERTIES, - "Set"); - if (!message) - return false; - - builder = l_dbus_message_builder_new(message); - if (!builder) { - l_dbus_message_unref(message); - return false; - } - - l_dbus_message_builder_append_basic(builder, 's', proxy->interface); - l_dbus_message_builder_append_basic(builder, 's', name); - - l_dbus_message_builder_enter_variant(builder, signature); - - va_start(args, signature); - l_dbus_message_builder_append_from_valist(builder, signature, args); - va_end(args); - - l_dbus_message_builder_leave_variant(builder); - - l_dbus_message_builder_finalize(builder); - l_dbus_message_builder_destroy(builder); - - req = l_new(struct method_call_request, 1); - req->proxy = proxy; - req->result = result; - req->user_data = user_data; - req->destroy = destroy; - - req->call_id = l_dbus_send_with_reply(client->dbus, message, - method_call_reply, req, - method_call_request_free); - if (!req->call_id) { - l_free(req); - return false; - } - - l_queue_push_tail(proxy->pending_calls, L_UINT_TO_PTR(req->call_id)); - - return true; -} - -LIB_EXPORT uint32_t l_dbus_proxy_method_call(struct l_dbus_proxy *proxy, - const char *method, - l_dbus_message_func_t setup, - l_dbus_client_proxy_result_func_t reply, - void *user_data, - l_dbus_destroy_func_t destroy) -{ - struct method_call_request *req; - - req = l_new(struct method_call_request, 1); - req->proxy = proxy; - req->setup = setup; - req->result = reply; - req->user_data = user_data; - req->destroy = destroy; - - req->call_id = l_dbus_method_call(proxy->client->dbus, - proxy->client->service, - proxy->path, proxy->interface, - method, method_call_setup, - method_call_reply, req, - method_call_request_free); - if (!req->call_id) { - l_free(req); - return 0; - } - - l_queue_push_tail(proxy->pending_calls, L_UINT_TO_PTR(req->call_id)); - - return req->call_id; -} - -static void proxy_update_property(struct l_dbus_proxy *proxy, - const char *name, - struct l_dbus_message_iter *property) -{ - struct l_dbus_message_builder *builder; - struct proxy_property *prop = get_property(proxy, name); - - l_dbus_message_unref(prop->msg); - - if (!property) { - prop->msg = NULL; - goto done; - } - - prop->msg = l_dbus_message_new_signal(proxy->client->dbus, proxy->path, - proxy->interface, name); - if (!prop->msg) - return; - - builder = l_dbus_message_builder_new(prop->msg); - l_dbus_message_builder_append_from_iter(builder, property); - l_dbus_message_builder_finalize(builder); - l_dbus_message_builder_destroy(builder); - -done: - if (proxy->client->properties_changed_cb && proxy->ready) - proxy->client->properties_changed_cb(proxy, name, prop->msg, - proxy->client->proxy_cb_data); -} - -static void proxy_invalidate_properties(struct l_dbus_proxy *proxy, - struct l_dbus_message_iter* props) -{ - const char *name; - - while (l_dbus_message_iter_next_entry(props, &name)) - proxy_update_property(proxy, name, NULL); -} - -static void proxy_update_properties(struct l_dbus_proxy *proxy, - struct l_dbus_message_iter* props) -{ - struct l_dbus_message_iter variant; - const char *name; - - while (l_dbus_message_iter_next_entry(props, &name, &variant)) - proxy_update_property(proxy, name, &variant); -} - -static void properties_changed_callback(struct l_dbus_message *message, - void *user_data) -{ - struct l_dbus_proxy *proxy = user_data; - const char *interface; - struct l_dbus_message_iter changed; - struct l_dbus_message_iter invalidated; - - if (!l_dbus_message_get_arguments(message, "sa{sv}as", &interface, - &changed, &invalidated)) - return; - - proxy_update_properties(proxy, &changed); - proxy_invalidate_properties(proxy, &invalidated); -} - -static struct l_dbus_proxy *dbus_proxy_new(struct l_dbus_client *client, - const char *path, const char *interface) -{ - struct l_dbus_proxy *proxy = l_new(struct l_dbus_proxy, 1); - - proxy->properties_watch = l_dbus_add_signal_watch(client->dbus, - client->service, path, - L_DBUS_INTERFACE_PROPERTIES, - "PropertiesChanged", - L_DBUS_MATCH_ARGUMENT(0), - interface, L_DBUS_MATCH_NONE, - properties_changed_callback, - proxy); - if (!proxy->properties_watch) { - l_free(proxy); - return NULL; - } - - proxy->client = client; - proxy->interface = l_strdup(interface); - proxy->path = l_strdup(path); - proxy->properties = l_queue_new(); - proxy->pending_calls = l_queue_new();; - - l_queue_push_tail(client->proxies, proxy); - - return proxy; -} - -static bool is_ignorable(const char *interface) -{ - static const struct { - const char *interface; - } interfaces_to_ignore[] = { - { L_DBUS_INTERFACE_OBJECT_MANAGER }, - { L_DBUS_INTERFACE_INTROSPECTABLE }, - { L_DBUS_INTERFACE_PROPERTIES }, - }; - size_t i; - - for (i = 0; i < L_ARRAY_SIZE(interfaces_to_ignore); i++) - if (!strcmp(interfaces_to_ignore[i].interface, interface)) - return true; - - return false; -} - -static struct l_dbus_proxy *find_proxy(struct l_dbus_client *client, - const char *path, const char *interface) -{ - const struct l_queue_entry *entry; - - for (entry = l_queue_get_entries(client->proxies); entry; - entry = entry->next) { - struct l_dbus_proxy *proxy = entry->data; - - if (!strcmp(proxy->interface, interface) && - !strcmp(proxy->path, path)) - return proxy; - } - - return NULL; -} - -static void parse_interface(struct l_dbus_client *client, const char *path, - const char *interface, - struct l_dbus_message_iter *properties) -{ - struct l_dbus_proxy *proxy; - - if (is_ignorable(interface)) - return; - - proxy = find_proxy(client, path, interface); - if (!proxy) - proxy = dbus_proxy_new(client, path, interface); - - if (!proxy) - return; - - proxy_update_properties(proxy, properties); - - if (!proxy->ready) { - proxy->ready = true; - - if (client->proxy_added_cb) - client->proxy_added_cb(proxy, client->proxy_cb_data); - } -} - -static void parse_object(struct l_dbus_client *client, const char *path, - struct l_dbus_message_iter *object) -{ - const char *interface; - struct l_dbus_message_iter properties; - - if (!path) - return; - - while (l_dbus_message_iter_next_entry(object, &interface, &properties)) - parse_interface(client, path, interface, &properties); -} - -static void interfaces_added_callback(struct l_dbus_message *message, - void *user_data) -{ - struct l_dbus_client *client = user_data; - struct l_dbus_message_iter object; - const char *path; - - if (!l_dbus_message_get_arguments(message, "oa{sa{sv}}", &path, - &object)) - return; - - parse_object(client, path, &object); -} - -static void interfaces_removed_callback(struct l_dbus_message *message, - void *user_data) -{ - struct l_dbus_client *client = user_data; - struct l_dbus_message_iter interfaces; - const char *interface; - const char *path; - - if (!l_dbus_message_get_arguments(message, "oas", &path, &interfaces)) - return; - - while (l_dbus_message_iter_next_entry(&interfaces, &interface)) { - struct l_dbus_proxy *proxy; - - proxy = find_proxy(client, path, interface); - if (!proxy) - continue; - - l_queue_remove(proxy->client->proxies, proxy); - - if (client->proxy_removed_cb) - client->proxy_removed_cb(proxy, client->proxy_cb_data); - - dbus_proxy_destroy(proxy); - } -} - -static void get_managed_objects_reply(struct l_dbus_message *message, - void *user_data) -{ - struct l_dbus_client *client = user_data; - struct l_dbus_message_iter objects; - struct l_dbus_message_iter object; - const char *path; - - client->objects_call = 0; - - if (l_dbus_message_is_error(message)) - return; - - if (!l_dbus_message_get_arguments(message, "a{oa{sa{sv}}}", &objects)) - return; - - while (l_dbus_message_iter_next_entry(&objects, &path, &object)) - parse_object(client, path, &object); - - client->added_watch = l_dbus_add_signal_watch(client->dbus, - client->service, "/", - L_DBUS_INTERFACE_OBJECT_MANAGER, - "InterfacesAdded", - L_DBUS_MATCH_NONE, - interfaces_added_callback, - client); - - client->removed_watch = l_dbus_add_signal_watch(client->dbus, - client->service, "/", - L_DBUS_INTERFACE_OBJECT_MANAGER, - "InterfacesRemoved", - L_DBUS_MATCH_NONE, - interfaces_removed_callback, - client); - - if (client->ready_cb) - client->ready_cb(client, client->ready_cb_data); -} - -static void service_appeared_callback(struct l_dbus *dbus, void *user_data) -{ - struct l_dbus_client *client = user_data; - - /* TODO should we allow to set different root? */ - client->objects_call = l_dbus_method_call(dbus, client->service, "/", - L_DBUS_INTERFACE_OBJECT_MANAGER, - "GetManagedObjects", NULL, - get_managed_objects_reply, - client, NULL); - - if (client->connect_cb) - client->connect_cb(client->dbus, client->connect_cb_data); -} - -static void service_disappeared_callback(struct l_dbus *dbus, void *user_data) -{ - struct l_dbus_client *client = user_data; - - if (client->disconnect_cb) - client->disconnect_cb(client->dbus, client->disconnect_cb_data); - - l_queue_clear(client->proxies, - (l_queue_destroy_func_t)dbus_proxy_destroy); -} - -LIB_EXPORT struct l_dbus_client *l_dbus_client_new(struct l_dbus *dbus, - const char *service, const char *path) -{ - struct l_dbus_client *client = l_new(struct l_dbus_client, 1); - - client->dbus = dbus; - - client->watch = l_dbus_add_service_watch(dbus, service, - service_appeared_callback, - service_disappeared_callback, - client, NULL); - - if (!client->watch) { - l_free(client); - return NULL; - } - - client->service = l_strdup(service); - client->proxies = l_queue_new(); - - return client; -} - -LIB_EXPORT void l_dbus_client_destroy(struct l_dbus_client *client) -{ - if (unlikely(!client)) - return; - - if (client->watch) - l_dbus_remove_signal_watch(client->dbus, client->watch); - - if (client->added_watch) - l_dbus_remove_signal_watch(client->dbus, client->added_watch); - - if (client->removed_watch) - l_dbus_remove_signal_watch(client->dbus, client->removed_watch); - - if (client->connect_cb_data_destroy) - client->connect_cb_data_destroy(client->connect_cb_data); - - if (client->disconnect_cb_data_destroy) - client->disconnect_cb_data_destroy(client->disconnect_cb_data); - - if (client->ready_cb_data_destroy) - client->ready_cb_data_destroy(client->ready_cb_data); - - if (client->proxy_cb_data_destroy) - client->proxy_cb_data_destroy(client->proxy_cb_data); - - if (client->objects_call) - l_dbus_cancel(client->dbus, client->objects_call) -; - l_queue_destroy(client->proxies, - (l_queue_destroy_func_t)dbus_proxy_destroy); - - l_free(client->service); - l_free(client); -} - -LIB_EXPORT bool l_dbus_client_set_connect_handler(struct l_dbus_client *client, - l_dbus_watch_func_t function, - void *user_data, - l_dbus_destroy_func_t destroy) -{ - if (unlikely(!client)) - return false; - - if (client->connect_cb_data_destroy) - client->connect_cb_data_destroy(client->connect_cb_data); - - client->connect_cb = function; - client->connect_cb_data = user_data; - client->connect_cb_data_destroy = destroy; - - return true; -} - -LIB_EXPORT bool l_dbus_client_set_disconnect_handler(struct l_dbus_client *client, - l_dbus_watch_func_t function, - void *user_data, - l_dbus_destroy_func_t destroy) -{ - if (unlikely(!client)) - return false; - - if(client->disconnect_cb_data_destroy) - client->disconnect_cb_data_destroy(client->disconnect_cb_data); - - client->disconnect_cb = function; - client->disconnect_cb_data = user_data; - client->disconnect_cb_data_destroy = destroy; - - return true; -} - -LIB_EXPORT bool l_dbus_client_set_ready_handler(struct l_dbus_client *client, - l_dbus_client_ready_func_t function, - void *user_data, - l_dbus_destroy_func_t destroy) -{ - if (unlikely(!client)) - return false; - - if (client->ready_cb_data_destroy) - client->ready_cb_data_destroy(client->ready_cb_data); - - client->ready_cb = function; - client->ready_cb_data = user_data; - client->ready_cb_data_destroy = destroy; - - return true; -} - -LIB_EXPORT bool l_dbus_client_set_proxy_handlers(struct l_dbus_client *client, - l_dbus_client_proxy_func_t proxy_added, - l_dbus_client_proxy_func_t proxy_removed, - l_dbus_client_property_function_t property_changed, - void *user_data, l_dbus_destroy_func_t destroy) -{ - if (unlikely(!client)) - return false; - - if (client->proxy_cb_data_destroy) - client->proxy_cb_data_destroy(client->proxy_cb_data); - - client->proxy_added_cb = proxy_added; - client->proxy_removed_cb = proxy_removed; - client->properties_changed_cb = property_changed; - client->proxy_cb_data = user_data; - client->proxy_cb_data_destroy = destroy; - - return true; -} diff --git a/ell/dbus-client.h b/ell/dbus-client.h deleted file mode 100644 index 699d824..0000000 --- a/ell/dbus-client.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * Copyright (C) 2017 Codecoup. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_DBUS_CLIENT_H -#define __ELL_DBUS_CLIENT_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_dbus; -struct l_dbus_message; -struct l_dbus_client; -struct l_dbus_proxy; - -typedef void (*l_dbus_client_ready_func_t)(struct l_dbus_client *client, - void *user_data); -typedef void (*l_dbus_client_proxy_func_t) (struct l_dbus_proxy *proxy, - void *user_data); -typedef void (*l_dbus_client_proxy_result_func_t) (struct l_dbus_proxy *proxy, - struct l_dbus_message *result, - void *user_data); -typedef void (*l_dbus_client_property_function_t) (struct l_dbus_proxy *proxy, - const char *name, - struct l_dbus_message *msg, - void *user_data); - -struct l_dbus_client *l_dbus_client_new(struct l_dbus *dbus, - const char *service, const char *path); -void l_dbus_client_destroy(struct l_dbus_client *client); - -bool l_dbus_client_set_connect_handler(struct l_dbus_client *client, - l_dbus_watch_func_t function, - void *user_data, - l_dbus_destroy_func_t destroy); - -bool l_dbus_client_set_disconnect_handler(struct l_dbus_client *client, - l_dbus_watch_func_t function, - void *user_data, - l_dbus_destroy_func_t destroy); - -bool l_dbus_client_set_ready_handler(struct l_dbus_client *client, - l_dbus_client_ready_func_t function, - void *user_data, - l_dbus_destroy_func_t destroy); - -bool l_dbus_client_set_proxy_handlers(struct l_dbus_client *client, - l_dbus_client_proxy_func_t proxy_added, - l_dbus_client_proxy_func_t proxy_removed, - l_dbus_client_property_function_t property_changed, - void *user_data, l_dbus_destroy_func_t destroy); - -const char *l_dbus_proxy_get_path(struct l_dbus_proxy *proxy); - -const char *l_dbus_proxy_get_interface(struct l_dbus_proxy *proxy); - -bool l_dbus_proxy_get_property(struct l_dbus_proxy *proxy, const char *name, - const char *signature, ...); - -bool l_dbus_proxy_set_property(struct l_dbus_proxy *proxy, - l_dbus_client_proxy_result_func_t result, - void *user_data, l_dbus_destroy_func_t destroy, - const char *name, const char *signature, ...); - -uint32_t l_dbus_proxy_method_call(struct l_dbus_proxy *proxy, - const char *method, - l_dbus_message_func_t setup, - l_dbus_client_proxy_result_func_t reply, - void *user_data, - l_dbus_destroy_func_t destroy); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_DBUS_CLIENT_H */ diff --git a/ell/dbus-filter.c b/ell/dbus-filter.c deleted file mode 100644 index 9a9b0f9..0000000 --- a/ell/dbus-filter.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2016 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include - -#include "util.h" -#include "queue.h" -#include "hashmap.h" -#include "string.h" -#include "dbus.h" -#include "dbus-private.h" -#include "gvariant-private.h" -#include "private.h" - -#define NODE_TYPE_CALLBACK L_DBUS_MATCH_NONE - -struct filter_node { - enum l_dbus_match_type type; - union { - struct { - char *value; - struct filter_node *children; - bool remote_rule; - } match; - struct { - l_dbus_message_func_t func; - void *user_data; - } callback; - }; - unsigned int id; - struct filter_node *next; -}; - -struct _dbus_filter { - struct l_dbus *dbus; - struct filter_node *root; - unsigned int signal_id; - unsigned int last_id; - const struct _dbus_filter_ops *driver; - struct _dbus_name_cache *name_cache; -}; - -static void filter_subtree_free(struct filter_node *node) -{ - struct filter_node *child, *next; - - if (node->type == NODE_TYPE_CALLBACK) { - l_free(node); - return; - } - - next = node->match.children; - - l_free(node->match.value); - l_free(node); - - while (next) { - child = next; - next = child->next; - - filter_subtree_free(child); - } -} - -static void dbus_filter_destroy(void *data) -{ - struct _dbus_filter *filter = data; - - if (filter->root) - filter_subtree_free(filter->root); - - l_free(filter); -} - -static void filter_dispatch_match_recurse(struct _dbus_filter *filter, - struct filter_node *node, - struct l_dbus_message *message) -{ - const char *value = NULL; - const char *alt_value = NULL; - struct filter_node *child; - - switch ((int) node->type) { - case NODE_TYPE_CALLBACK: - node->callback.func(message, node->callback.user_data); - return; - - case L_DBUS_MATCH_SENDER: - value = l_dbus_message_get_sender(message); - break; - - case L_DBUS_MATCH_TYPE: - value = _dbus_message_get_type_as_string(message); - break; - - case L_DBUS_MATCH_PATH: - value = l_dbus_message_get_path(message); - break; - - case L_DBUS_MATCH_INTERFACE: - value = l_dbus_message_get_interface(message); - break; - - case L_DBUS_MATCH_MEMBER: - value = l_dbus_message_get_member(message); - break; - - case L_DBUS_MATCH_ARG0...(L_DBUS_MATCH_ARG0 + 63): - value = _dbus_message_get_nth_string_argument(message, - node->type - L_DBUS_MATCH_ARG0); - break; - } - - if (!value) - return; - - if (node->type == L_DBUS_MATCH_SENDER && filter->name_cache) - alt_value = _dbus_name_cache_lookup(filter->name_cache, - node->match.value); - - if (strcmp(value, node->match.value) && - (!alt_value || strcmp(value, alt_value))) - return; - - for (child = node->match.children; child; child = child->next) - filter_dispatch_match_recurse(filter, child, message); -} - -void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data) -{ - struct _dbus_filter *filter = user_data; - - filter_dispatch_match_recurse(filter, filter->root, message); -} - -struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus, - const struct _dbus_filter_ops *driver, - struct _dbus_name_cache *name_cache) -{ - struct _dbus_filter *filter; - - filter = l_new(struct _dbus_filter, 1); - - filter->dbus = dbus; - filter->driver = driver; - filter->name_cache = name_cache; - - if (!filter->driver->skip_register) - filter->signal_id = l_dbus_register(dbus, _dbus_filter_dispatch, - filter, - dbus_filter_destroy); - - return filter; -} - -void _dbus_filter_free(struct _dbus_filter *filter) -{ - if (!filter) - return; - - if (!filter->driver->skip_register) - l_dbus_unregister(filter->dbus, filter->signal_id); - else - dbus_filter_destroy(filter); -} - -static int condition_compare(const void *a, const void *b) -{ - const struct _dbus_filter_condition *condition_a = a, *condition_b = b; - - return condition_a->type - condition_b->type; -} - -static bool remove_recurse(struct _dbus_filter *filter, - struct filter_node **node, unsigned int id) -{ - struct filter_node *tmp; - - for (; *node; node = &(*node)->next) { - if ((*node)->type == NODE_TYPE_CALLBACK && (*node)->id == id) - break; - - if ((*node)->type != NODE_TYPE_CALLBACK && - remove_recurse(filter, &(*node)->match.children, - id)) - break; - } - - if (!*node) - return false; - - if ((*node)->type == NODE_TYPE_CALLBACK || !(*node)->match.children) { - tmp = *node; - *node = tmp->next; - - if (tmp->match.remote_rule) - filter->driver->remove_match(filter->dbus, tmp->id); - - if (tmp->type == L_DBUS_MATCH_SENDER && filter->name_cache && - !_dbus_parse_unique_name(tmp->match.value, - NULL)) - _dbus_name_cache_remove(filter->name_cache, - tmp->match.value); - - filter_subtree_free(tmp); - } - - return true; -} - -unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter, - const struct _dbus_filter_condition *rule, - int rule_len, - l_dbus_message_func_t signal_func, - void *user_data) -{ - struct filter_node **node_ptr = &filter->root; - struct filter_node *node; - struct filter_node *parent = filter->root; - bool remote_rule = false; - struct _dbus_filter_condition sorted[rule_len]; - struct _dbus_filter_condition *unused, *condition; - struct _dbus_filter_condition *end = sorted + rule_len; - - memcpy(sorted, rule, sizeof(sorted)); - qsort(sorted, rule_len, sizeof(*condition), condition_compare); - - /* - * Find or create a path in the tree with a node for each - * condition in the rule, loop until all conditions have been - * used. - */ - unused = sorted; - while (unused < end) { - /* - * Find a child of the node that matches any unused - * condition. Note there could be multiple matches, we're - * happy with the first we can find. - */ - while (*node_ptr) { - node = *node_ptr; - - for (condition = unused; condition < end; condition++) { - if (condition->type > node->type) { - condition = end; - break; - } - - if (condition->type < node->type || - condition->type == - L_DBUS_MATCH_NONE) - continue; - - if (!strcmp(node->match.value, - condition->value)) - break; - } - - if (condition < end) - break; - - node_ptr = &node->next; - } - - /* Add a node */ - if (!*node_ptr) { - condition = unused; - - node = l_new(struct filter_node, 1); - node->type = condition->type; - node->match.value = l_strdup(condition->value); - - *node_ptr = node; - - if (node->type == L_DBUS_MATCH_SENDER && - filter->name_cache && - !_dbus_parse_unique_name( - node->match.value, - NULL)) - _dbus_name_cache_add(filter->name_cache, - node->match.value); - - } - - /* - * Mark the condition used. We do this by setting - * condition->type to an invalid value unless it is the - * first condition left in which case we can push the - * rule start. Another option is to always push the rule - * start and memmove the still unused conditions by one - * if necessary. - */ - condition->type = L_DBUS_MATCH_NONE; - while (unused < end && unused[0].type == L_DBUS_MATCH_NONE) - unused++; - - node_ptr = &node->match.children; - - parent = node; - - /* - * Only have to call AddMatch if none of the parent nodes - * have yet created an AddMatch rule on the server. - */ - remote_rule |= node->match.remote_rule; - } - - node = l_new(struct filter_node, 1); - node->type = NODE_TYPE_CALLBACK; - node->callback.func = signal_func; - node->callback.user_data = user_data; - node->id = ++filter->last_id; - node->next = *node_ptr; - - *node_ptr = node; - - if (!remote_rule) { - if (!filter->driver->add_match(filter->dbus, node->id, - rule, rule_len)) - goto err; - - parent->id = node->id; - parent->match.remote_rule = true; - } - - return node->id; - -err: - /* Remove all the nodes we may have added */ - node->id = (unsigned int) -1; - remove_recurse(filter, &filter->root, node->id); - - return 0; -} - -bool _dbus_filter_remove_rule(struct _dbus_filter *filter, unsigned int id) -{ - return remove_recurse(filter, &filter->root, id); -} - -char *_dbus_filter_rule_to_str(const struct _dbus_filter_condition *rule, - int rule_len) -{ - struct l_string *str = l_string_new(63); - char *key, arg_buf[6]; - const char *value, *endp; - - for (; rule_len; rule++, rule_len--) { - switch ((int) rule->type) { - case L_DBUS_MATCH_SENDER: - key = "sender"; - break; - case L_DBUS_MATCH_TYPE: - key = "type"; - break; - case L_DBUS_MATCH_PATH: - key = "path"; - break; - case L_DBUS_MATCH_INTERFACE: - key = "interface"; - break; - case L_DBUS_MATCH_MEMBER: - key = "member"; - break; - case L_DBUS_MATCH_ARG0...(L_DBUS_MATCH_ARG0 + 63): - key = arg_buf; - snprintf(arg_buf, sizeof(arg_buf), "arg%i", - rule->type - L_DBUS_MATCH_ARG0); - break; - default: - l_string_free(str); - return NULL; - } - - l_string_append(str, key); - l_string_append(str, "='"); - - /* We only need to escape single-quotes in the values */ - value = rule->value; - - while ((endp = strchr(value, '\''))) { - l_string_append_fixed(str, value, endp - value); - l_string_append(str, "'\\''"); - - value = endp + 1; - } - - l_string_append(str, value); - l_string_append_c(str, '\''); - - if (rule_len > 1) - l_string_append_c(str, ','); - } - - return l_string_unwrap(str); -} diff --git a/ell/dbus-message.c b/ell/dbus-message.c deleted file mode 100644 index f77df9d..0000000 --- a/ell/dbus-message.c +++ /dev/null @@ -1,1991 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include - -#include "util.h" -#include "private.h" -#include "dbus.h" -#include "dbus-private.h" -#include "gvariant-private.h" - -#define DBUS_MESSAGE_LITTLE_ENDIAN ('l') -#define DBUS_MESSAGE_BIG_ENDIAN ('B') - -#define DBUS_MESSAGE_PROTOCOL_VERSION 1 - -#define DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED 0x01 -#define DBUS_MESSAGE_FLAG_NO_AUTO_START 0x02 - -#define DBUS_MESSAGE_FIELD_PATH 1 -#define DBUS_MESSAGE_FIELD_INTERFACE 2 -#define DBUS_MESSAGE_FIELD_MEMBER 3 -#define DBUS_MESSAGE_FIELD_ERROR_NAME 4 -#define DBUS_MESSAGE_FIELD_REPLY_SERIAL 5 -#define DBUS_MESSAGE_FIELD_DESTINATION 6 -#define DBUS_MESSAGE_FIELD_SENDER 7 -#define DBUS_MESSAGE_FIELD_SIGNATURE 8 -#define DBUS_MESSAGE_FIELD_UNIX_FDS 9 - -#define DBUS_MAX_NESTING 32 - -struct l_dbus_message { - int refcount; - void *header; - size_t header_size; - size_t header_end; - char *signature; - void *body; - size_t body_size; - char *path; - char *interface; - char *member; - char *error_name; - uint32_t reply_serial; - char *destination; - char *sender; - int fds[16]; - uint32_t num_fds; - - bool sealed : 1; - bool signature_free : 1; -}; - -struct l_dbus_message_builder { - struct l_dbus_message *message; - struct dbus_builder *builder; - struct builder_driver *driver; -}; - -static inline bool _dbus_message_is_gvariant(struct l_dbus_message *msg) -{ - struct dbus_header *hdr = msg->header; - - return hdr->version == 2; -} - -void *_dbus_message_get_header(struct l_dbus_message *msg, size_t *out_size) -{ - if (out_size) - *out_size = msg->header_size; - - return msg->header; -} - -void *_dbus_message_get_body(struct l_dbus_message *msg, size_t *out_size) -{ - if (out_size) - *out_size = msg->body_size; - - return msg->body; -} - -/* Get a buffer containing the final message contents except the header */ -void *_dbus_message_get_footer(struct l_dbus_message *msg, size_t *out_size) -{ - size_t size; - - if (_dbus_message_is_gvariant(msg)) { - size = _gvariant_message_finalize(msg->header_end, - msg->body, msg->body_size, - msg->signature); - size -= msg->header_size; - } else - size = msg->body_size; - - if (out_size) - *out_size = size; - - return msg->body; -} - -int *_dbus_message_get_fds(struct l_dbus_message *msg, uint32_t *num_fds) -{ - *num_fds = msg->num_fds; - - return msg->fds; -} - -void _dbus_message_set_serial(struct l_dbus_message *msg, uint32_t serial) -{ - struct dbus_header *hdr = msg->header; - - hdr->dbus1.serial = serial; -} - -uint32_t _dbus_message_get_serial(struct l_dbus_message *msg) -{ - struct dbus_header *hdr = msg->header; - - return hdr->dbus1.serial; -} - -LIB_EXPORT bool l_dbus_message_set_no_reply(struct l_dbus_message *msg, bool on) -{ - struct dbus_header *hdr; - - if (unlikely(!msg)) - return false; - - hdr = msg->header; - - if (on) - hdr->flags |= DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED; - else - hdr->flags &= ~DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED; - - return true; -} - -LIB_EXPORT bool l_dbus_message_get_no_reply(struct l_dbus_message *msg) -{ - struct dbus_header *hdr; - - if (unlikely(!msg)) - return false; - - hdr = msg->header; - - if (hdr->flags & DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED) - return true; - - return false; -} - -LIB_EXPORT bool l_dbus_message_set_no_autostart(struct l_dbus_message *msg, - bool on) -{ - struct dbus_header *hdr; - - if (unlikely(!msg)) - return false; - - hdr = msg->header; - - if (on) - hdr->flags |= DBUS_MESSAGE_FLAG_NO_AUTO_START; - else - hdr->flags &= ~DBUS_MESSAGE_FLAG_NO_AUTO_START; - - return true; -} - -LIB_EXPORT bool l_dbus_message_get_no_autostart(struct l_dbus_message *msg) -{ - struct dbus_header *hdr; - - if (unlikely(!msg)) - return false; - - hdr = msg->header; - - if (hdr->flags & DBUS_MESSAGE_FLAG_NO_AUTO_START) - return true; - - return false; - -} - -static struct l_dbus_message *message_new_common(uint8_t type, uint8_t flags, - uint8_t version) -{ - struct l_dbus_message *message; - struct dbus_header *hdr; - - message = l_new(struct l_dbus_message, 1); - message->refcount = 1; - - /* - * We allocate the header with the initial 12 bytes (up to the field - * length) so that we can store the basic information here. For - * GVariant we need 16 bytes. - */ - message->header_size = version == 1 ? 12 : 16; - message->header_end = message->header_size; - message->header = l_realloc(NULL, message->header_size); - - hdr = message->header; - hdr->endian = DBUS_NATIVE_ENDIAN; - hdr->message_type = type; - hdr->flags = flags; - hdr->version = version; - - return message; -} - -struct l_dbus_message *_dbus_message_new_method_call(uint8_t version, - const char *destination, - const char *path, - const char *interface, - const char *method) -{ - struct l_dbus_message *message; - - message = message_new_common(DBUS_MESSAGE_TYPE_METHOD_CALL, 0, version); - - message->destination = l_strdup(destination); - message->path = l_strdup(path); - message->interface = l_strdup(interface); - message->member = l_strdup(method); - - return message; -} - -LIB_EXPORT struct l_dbus_message *l_dbus_message_new_method_call( - struct l_dbus *dbus, - const char *destination, - const char *path, - const char *interface, - const char *method) -{ - uint8_t version; - - if (unlikely(!dbus)) - return NULL; - - version = _dbus_get_version(dbus); - - return _dbus_message_new_method_call(version, destination, path, - interface, method); -} - -struct l_dbus_message *_dbus_message_new_signal(uint8_t version, - const char *path, - const char *interface, - const char *name) -{ - struct l_dbus_message *message; - - message = message_new_common(DBUS_MESSAGE_TYPE_SIGNAL, - DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED, - version); - - message->path = l_strdup(path); - message->interface = l_strdup(interface); - message->member = l_strdup(name); - - return message; -} - -LIB_EXPORT struct l_dbus_message *l_dbus_message_new_signal(struct l_dbus *dbus, - const char *path, - const char *interface, - const char *name) -{ - uint8_t version; - - if (unlikely(!dbus)) - return NULL; - - version = _dbus_get_version(dbus); - - return _dbus_message_new_signal(version, path, interface, name); -} - -LIB_EXPORT struct l_dbus_message *l_dbus_message_new_method_return( - struct l_dbus_message *method_call) -{ - struct l_dbus_message *message; - struct dbus_header *hdr = method_call->header; - const char *sender; - - message = message_new_common(DBUS_MESSAGE_TYPE_METHOD_RETURN, - DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED, - hdr->version); - - if (!l_dbus_message_get_no_reply(method_call)) - message->reply_serial = _dbus_message_get_serial(method_call); - - sender = l_dbus_message_get_sender(method_call); - if (sender) - message->destination = l_strdup(sender); - - return message; -} - -struct l_dbus_message *_dbus_message_new_error(uint8_t version, - uint32_t reply_serial, - const char *destination, - const char *name, - const char *error) -{ - struct l_dbus_message *reply; - - if (!_dbus_valid_interface(name)) - return NULL; - - reply = message_new_common(DBUS_MESSAGE_TYPE_ERROR, - DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED, - version); - - reply->error_name = l_strdup(name); - reply->destination = l_strdup(destination); - reply->reply_serial = reply_serial; - - if (!l_dbus_message_set_arguments(reply, "s", error)) { - l_dbus_message_unref(reply); - return NULL; - } - - return reply; -} - -LIB_EXPORT struct l_dbus_message *l_dbus_message_new_error_valist( - struct l_dbus_message *method_call, - const char *name, - const char *format, va_list args) -{ - char str[1024]; - struct dbus_header *hdr = method_call->header; - uint32_t reply_serial = 0; - - vsnprintf(str, sizeof(str), format, args); - - if (!l_dbus_message_get_no_reply(method_call)) - reply_serial = _dbus_message_get_serial(method_call); - - return _dbus_message_new_error(hdr->version, reply_serial, - l_dbus_message_get_sender(method_call), - name, str); -} - -LIB_EXPORT struct l_dbus_message *l_dbus_message_new_error( - struct l_dbus_message *method_call, - const char *name, - const char *format, ...) -{ - va_list args; - struct l_dbus_message *reply; - - va_start(args, format); - reply = l_dbus_message_new_error_valist(method_call, name, - format, args); - va_end(args); - - return reply; -} - -LIB_EXPORT struct l_dbus_message *l_dbus_message_ref(struct l_dbus_message *message) -{ - if (unlikely(!message)) - return NULL; - - __sync_fetch_and_add(&message->refcount, 1); - - return message; -} - -LIB_EXPORT void l_dbus_message_unref(struct l_dbus_message *message) -{ - unsigned int i; - - if (unlikely(!message)) - return; - - if (__sync_sub_and_fetch(&message->refcount, 1)) - return; - - for (i = 0; i < message->num_fds; i++) - close(message->fds[i]); - - if (!message->sealed) { - l_free(message->destination); - l_free(message->path); - l_free(message->interface); - l_free(message->member); - l_free(message->error_name); - l_free(message->sender); - } - - if (message->signature_free) - l_free(message->signature); - - l_free(message->header); - l_free(message->body); - l_free(message); -} - -const char *_dbus_message_get_nth_string_argument( - struct l_dbus_message *message, int n) -{ - struct l_dbus_message_iter iter; - const char *signature, *value; - void *body; - size_t size; - char type; - bool (*skip_entry)(struct l_dbus_message_iter *); - bool (*get_basic)(struct l_dbus_message_iter *, char, void *); - - signature = l_dbus_message_get_signature(message); - body = _dbus_message_get_body(message, &size); - - if (!signature) - return NULL; - - if (_dbus_message_is_gvariant(message)) { - if (!_gvariant_iter_init(&iter, message, signature, NULL, - body, size)) - return NULL; - - skip_entry = _gvariant_iter_skip_entry; - get_basic = _gvariant_iter_next_entry_basic; - } else { - _dbus1_iter_init(&iter, message, signature, NULL, body, size); - - skip_entry = _dbus1_iter_skip_entry; - get_basic = _dbus1_iter_next_entry_basic; - } - - while (n--) - if (!skip_entry(&iter)) - return NULL; - - if (!iter.sig_start) - return NULL; - - type = iter.sig_start[iter.sig_pos]; - if (!strchr("sog", type)) - return NULL; - - if (!get_basic(&iter, type, &value)) - return NULL; - - return value; -} - -static bool message_iter_next_entry_valist(struct l_dbus_message_iter *orig, - va_list args) -{ - static const char *simple_types = "sogybnqiuxtd"; - struct l_dbus_message_iter *iter = orig; - const char *signature = orig->sig_start + orig->sig_pos; - const char *end; - struct l_dbus_message_iter *sub_iter; - struct l_dbus_message_iter stack[DBUS_MAX_NESTING]; - unsigned int indent = 0; - uint32_t uint32_val; - int fd; - void *arg; - bool (*get_basic)(struct l_dbus_message_iter *, char ,void *); - bool (*enter_struct)(struct l_dbus_message_iter *, - struct l_dbus_message_iter *); - bool (*enter_array)(struct l_dbus_message_iter *, - struct l_dbus_message_iter *); - bool (*enter_variant)(struct l_dbus_message_iter *, - struct l_dbus_message_iter *); - - if (_dbus_message_is_gvariant(orig->message)) { - get_basic = _gvariant_iter_next_entry_basic; - enter_struct = _gvariant_iter_enter_struct; - enter_array = _gvariant_iter_enter_array; - enter_variant = _gvariant_iter_enter_variant; - } else { - get_basic = _dbus1_iter_next_entry_basic; - enter_struct = _dbus1_iter_enter_struct; - enter_array = _dbus1_iter_enter_array; - enter_variant = _dbus1_iter_enter_variant; - } - - while (signature < orig->sig_start + orig->sig_len) { - if (strchr(simple_types, *signature)) { - arg = va_arg(args, void *); - if (!get_basic(iter, *signature, arg)) - return false; - - signature += 1; - continue; - } - - switch (*signature) { - case 'h': - if (!get_basic(iter, 'h', &uint32_val)) - return false; - - if (uint32_val < iter->message->num_fds) - fd = fcntl(iter->message->fds[uint32_val], - F_DUPFD_CLOEXEC, 3); - else - fd = -1; - - *va_arg(args, int *) = fd; - signature += 1; - break; - case '(': - case '{': - signature += 1; - indent += 1; - - if (indent > DBUS_MAX_NESTING) - return false; - - if (!enter_struct(iter, &stack[indent - 1])) - return false; - - iter = &stack[indent - 1]; - - break; - case ')': - case '}': - /* - * Sanity check in case of an unmatched paren/brace - * that isn't caught elsewhere. - */ - if (unlikely(indent == 0)) - return false; - - signature += 1; - indent -= 1; - - if (indent == 0) - iter = orig; - else - iter = &stack[indent - 1]; - break; - case 'a': - sub_iter = va_arg(args, void *); - - if (!enter_array(iter, sub_iter)) - return false; - - end = _dbus_signature_end(signature + 1); - signature = end + 1; - break; - case 'v': - sub_iter = va_arg(args, void *); - - if (!enter_variant(iter, sub_iter)) - return false; - - signature += 1; - break; - default: - return false; - } - } - - return true; -} - -static inline bool message_iter_next_entry(struct l_dbus_message_iter *iter, - ...) -{ - va_list args; - bool result; - - va_start(args, iter); - result = message_iter_next_entry_valist(iter, args); - va_end(args); - - return result; -} - -static bool get_header_field_from_iter_valist(struct l_dbus_message *message, - uint8_t type, char data_type, - va_list args) -{ - struct l_dbus_message_iter header; - struct l_dbus_message_iter array, iter; - uint8_t endian, message_type, flags, version; - uint32_t body_length, serial; - bool found; - - if (!message->sealed) - return false; - - if (_dbus_message_is_gvariant(message)) { - uint64_t field_type; - - if (!_gvariant_iter_init(&header, message, "a(tv)", NULL, - message->header + 16, - message->header_end - 16)) - return false; - - if (!_gvariant_iter_enter_array(&header, &array)) - return false; - - while ((found = message_iter_next_entry(&array, - &field_type, &iter))) - if (field_type == type) - break; - } else { - uint8_t field_type; - - _dbus1_iter_init(&header, message, "yyyyuua(yv)", NULL, - message->header, message->header_size); - - if (!message_iter_next_entry(&header, &endian, - &message_type, &flags, &version, - &body_length, &serial, &array)) - return false; - - while ((found = message_iter_next_entry(&array, - &field_type, &iter))) - if (field_type == type) - break; - } - - if (!found) - return false; - - if (iter.sig_start[iter.sig_pos] != data_type) - return false; - - return message_iter_next_entry_valist(&iter, args); -} - -static inline bool get_header_field(struct l_dbus_message *message, - uint8_t type, int data_type, ...) -{ - va_list args; - bool result; - - va_start(args, data_type); - result = get_header_field_from_iter_valist(message, type, data_type, - args); - va_end(args); - - return result; -} - -static bool valid_header(const struct dbus_header *hdr) -{ - if (hdr->endian != DBUS_MESSAGE_LITTLE_ENDIAN && - hdr->endian != DBUS_MESSAGE_BIG_ENDIAN) - return false; - - if (hdr->message_type < DBUS_MESSAGE_TYPE_METHOD_CALL || - hdr->message_type > DBUS_MESSAGE_TYPE_SIGNAL) - return false; - - if (hdr->version != 1 && hdr->version != 2) - return false; - - if (hdr->version == 1) { - if (hdr->dbus1.serial == 0) - return false; - } - - return true; -} - -unsigned int _dbus_message_unix_fds_from_header(const void *data, size_t size) -{ - struct l_dbus_message message; - uint32_t unix_fds; - - message.header = (uint8_t *) data; - message.header_size = size; - message.body_size = 0; - message.sealed = true; - - if (!get_header_field(&message, DBUS_MESSAGE_FIELD_UNIX_FDS, - 'u', &unix_fds)) - return 0; - - return unix_fds; -} - -struct l_dbus_message *dbus_message_from_blob(const void *data, size_t size, - int fds[], uint32_t num_fds) -{ - const struct dbus_header *hdr = data; - struct l_dbus_message *message; - size_t body_pos; - unsigned int i; - - if (unlikely(size < DBUS_HEADER_SIZE)) - return NULL; - - message = l_new(struct l_dbus_message, 1); - - message->refcount = 1; - - if (hdr->version == 1) { - message->header_size = align_len(DBUS_HEADER_SIZE + - hdr->dbus1.field_length, 8); - message->body_size = hdr->dbus1.body_length; - - if (message->header_size + message->body_size < size) - goto free; - - body_pos = message->header_size; - } else { - struct l_dbus_message_iter iter; - struct l_dbus_message_iter header, variant, body; - - /* - * GVariant message structure as per - * https://wiki.gnome.org/Projects/GLib/GDBus/Version2 - * is "(yyyyuta{tv}v)". As noted this is equivalent to - * some other types, this one lets us get iterators for - * the header and the body in the fewest steps. - */ - if (!_gvariant_iter_init(&iter, message, "(yyyyuta{tv})v", - NULL, data, size)) - goto free; - - if (!_gvariant_iter_enter_struct(&iter, &header)) - goto free; - - if (!_gvariant_iter_enter_variant(&iter, &variant)) - goto free; - - if (!_gvariant_iter_enter_struct(&variant, &body)) - goto free; - - message->header_size = align_len(header.len - header.pos, 8); - message->body_size = body.len - body.pos; - message->signature = l_strndup(body.sig_start + body.sig_pos, - body.sig_len - body.sig_pos); - message->signature_free = true; - message->header_end = header.len; - body_pos = body.data + body.pos - data; - } - - message->header = l_malloc(message->header_size); - message->body = l_malloc(message->body_size); - - memcpy(message->header, data, message->header_size); - memcpy(message->body, data + body_pos, message->body_size); - - message->sealed = true; - - /* If the field is absent message->signature will remain NULL */ - if (hdr->version == 1) - get_header_field(message, DBUS_MESSAGE_FIELD_SIGNATURE, - 'g', &message->signature); - - if (num_fds) { - uint32_t unix_fds, orig_fds = num_fds; - - if (!get_header_field(message, DBUS_MESSAGE_FIELD_UNIX_FDS, - 'u', &unix_fds)) - goto free; - - if (num_fds > unix_fds) - num_fds = unix_fds; - - if (num_fds > L_ARRAY_SIZE(message->fds)) - num_fds = L_ARRAY_SIZE(message->fds); - - for (i = num_fds; i < orig_fds; i++) - close(fds[i]); - - message->num_fds = num_fds; - memcpy(message->fds, fds, num_fds * sizeof(int)); - } - - return message; - -free: - l_dbus_message_unref(message); - - return NULL; -} - -struct l_dbus_message *dbus_message_build(void *header, size_t header_size, - void *body, size_t body_size, - int fds[], uint32_t num_fds) -{ - const struct dbus_header *hdr = header; - struct l_dbus_message *message; - unsigned int i; - - if (unlikely(header_size < DBUS_HEADER_SIZE)) - return NULL; - - if (unlikely(!valid_header(hdr))) - return NULL; - - /* - * With GVariant we need to know the signature, use - * dbus_message_from_blob instead. - */ - if (unlikely(hdr->version != 1)) - return NULL; - - message = l_new(struct l_dbus_message, 1); - - message->refcount = 1; - message->header_size = header_size; - message->header = header; - message->body_size = body_size; - message->body = body; - message->sealed = true; - - if (num_fds) { - uint32_t unix_fds, orig_fds = num_fds; - - if (!get_header_field(message, DBUS_MESSAGE_FIELD_UNIX_FDS, - 'u', &unix_fds)) { - l_free(message); - return NULL; - } - - if (num_fds > unix_fds) - num_fds = unix_fds; - - if (num_fds > L_ARRAY_SIZE(message->fds)) - num_fds = L_ARRAY_SIZE(message->fds); - - for (i = num_fds; i < orig_fds; i++) - close(fds[i]); - - message->num_fds = num_fds; - memcpy(message->fds, fds, num_fds * sizeof(int)); - } - - /* If the field is absent message->signature will remain NULL */ - get_header_field(message, DBUS_MESSAGE_FIELD_SIGNATURE, 'g', - &message->signature); - - return message; -} - -bool dbus_message_compare(struct l_dbus_message *message, - const void *data, size_t size) -{ - struct l_dbus_message *other; - bool ret = false; - - other = dbus_message_from_blob(data, size, NULL, 0); - - if (message->signature) { - if (!other->signature) - goto done; - - if (strcmp(message->signature, other->signature)) - goto done; - } else { - if (other->signature) - goto done; - } - - if (message->body_size != other->body_size) - goto done; - - if (message->header_size != other->header_size) - goto done; - - ret = !memcmp(message->body, other->body, message->body_size); - -done: - l_dbus_message_unref(other); - - return ret; -} - -struct builder_driver { - bool (*append_basic)(struct dbus_builder *, char, const void *); - bool (*enter_struct)(struct dbus_builder *, const char *); - bool (*leave_struct)(struct dbus_builder *); - bool (*enter_dict)(struct dbus_builder *, const char *); - bool (*leave_dict)(struct dbus_builder *); - bool (*enter_array)(struct dbus_builder *, const char *); - bool (*leave_array)(struct dbus_builder *); - bool (*enter_variant)(struct dbus_builder *, const char *); - bool (*leave_variant)(struct dbus_builder *); - char *(*finish)(struct dbus_builder *, void **, size_t *); - bool (*mark)(struct dbus_builder *); - bool (*rewind)(struct dbus_builder *); - struct dbus_builder *(*new)(void *, size_t); - void (*free)(struct dbus_builder *); -}; - -static struct builder_driver dbus1_driver = { - .append_basic = _dbus1_builder_append_basic, - .enter_struct = _dbus1_builder_enter_struct, - .leave_struct = _dbus1_builder_leave_struct, - .enter_dict = _dbus1_builder_enter_dict, - .leave_dict = _dbus1_builder_leave_dict, - .enter_variant = _dbus1_builder_enter_variant, - .leave_variant = _dbus1_builder_leave_variant, - .enter_array = _dbus1_builder_enter_array, - .leave_array = _dbus1_builder_leave_array, - .finish = _dbus1_builder_finish, - .mark = _dbus1_builder_mark, - .rewind = _dbus1_builder_rewind, - .new = _dbus1_builder_new, - .free = _dbus1_builder_free, -}; - -static struct builder_driver gvariant_driver = { - .append_basic = _gvariant_builder_append_basic, - .enter_struct = _gvariant_builder_enter_struct, - .leave_struct = _gvariant_builder_leave_struct, - .enter_dict = _gvariant_builder_enter_dict, - .leave_dict = _gvariant_builder_leave_dict, - .enter_variant = _gvariant_builder_enter_variant, - .leave_variant = _gvariant_builder_leave_variant, - .enter_array = _gvariant_builder_enter_array, - .leave_array = _gvariant_builder_leave_array, - .finish = _gvariant_builder_finish, - .mark = _gvariant_builder_mark, - .rewind = _gvariant_builder_rewind, - .new = _gvariant_builder_new, - .free = _gvariant_builder_free, -}; - -static void add_field(struct dbus_builder *builder, - struct builder_driver *driver, - uint8_t field, const char *type, const void *value) -{ - if (driver == &gvariant_driver) { - uint64_t long_field = field; - - driver->enter_struct(builder, "tv"); - driver->append_basic(builder, 't', &long_field); - } else { - driver->enter_struct(builder, "yv"); - driver->append_basic(builder, 'y', &field); - } - driver->enter_variant(builder, type); - driver->append_basic(builder, type[0], value); - driver->leave_variant(builder); - driver->leave_struct(builder); -} - -static void build_header(struct l_dbus_message *message, const char *signature) -{ - struct dbus_builder *builder; - struct builder_driver *driver; - char *generated_signature; - size_t header_size; - bool gvariant; - - gvariant = _dbus_message_is_gvariant(message); - - if (gvariant) - driver = &gvariant_driver; - else - driver = &dbus1_driver; - - builder = driver->new(message->header, message->header_size); - - driver->enter_array(builder, gvariant ? "(tv)" : "(yv)"); - - if (message->path) { - add_field(builder, driver, DBUS_MESSAGE_FIELD_PATH, - "o", message->path); - l_free(message->path); - message->path = NULL; - } - - if (message->member) { - add_field(builder, driver, DBUS_MESSAGE_FIELD_MEMBER, - "s", message->member); - l_free(message->member); - message->member = NULL; - } - - if (message->interface) { - add_field(builder, driver, DBUS_MESSAGE_FIELD_INTERFACE, - "s", message->interface); - l_free(message->interface); - message->interface = NULL; - } - - if (message->destination) { - add_field(builder, driver, DBUS_MESSAGE_FIELD_DESTINATION, - "s", message->destination); - l_free(message->destination); - message->destination = NULL; - } - - if (message->error_name != 0) { - add_field(builder, driver, DBUS_MESSAGE_FIELD_ERROR_NAME, - "s", message->error_name); - l_free(message->error_name); - message->error_name = NULL; - } - - if (message->reply_serial != 0) { - if (gvariant) { - uint64_t reply_serial = message->reply_serial; - - add_field(builder, driver, - DBUS_MESSAGE_FIELD_REPLY_SERIAL, - "t", &reply_serial); - } else { - add_field(builder, driver, - DBUS_MESSAGE_FIELD_REPLY_SERIAL, - "u", &message->reply_serial); - } - - message->reply_serial = 0; - } - - if (message->sender) { - add_field(builder, driver, DBUS_MESSAGE_FIELD_SENDER, - "s", message->sender); - l_free(message->sender); - message->sender = NULL; - } - - if (signature[0] != '\0' && !gvariant) - add_field(builder, driver, DBUS_MESSAGE_FIELD_SIGNATURE, - "g", signature); - - if (message->num_fds) - add_field(builder, driver, DBUS_MESSAGE_FIELD_UNIX_FDS, - "u", &message->num_fds); - - driver->leave_array(builder); - - generated_signature = driver->finish(builder, &message->header, - &header_size); - l_free(generated_signature); - - driver->free(builder); - - if (!_dbus_message_is_gvariant(message)) { - struct dbus_header *hdr = message->header; - - hdr->dbus1.body_length = message->body_size; - } - - /* We must align the end of the header to an 8-byte boundary */ - message->header_size = align_len(header_size, 8); - message->header = l_realloc(message->header, message->header_size); - memset(message->header + header_size, 0, - message->header_size - header_size); - message->header_end = header_size; -} - -struct container { - char type; - const char *sig_start; - const char *sig_end; - unsigned int n_items; -}; - -static bool append_arguments(struct l_dbus_message *message, - const char *signature, va_list args) -{ - struct l_dbus_message_builder *builder; - bool ret; - - builder = l_dbus_message_builder_new(message); - if (!builder) - return false; - - if (!l_dbus_message_builder_append_from_valist(builder, signature, - args)) { - l_dbus_message_builder_destroy(builder); - return false; - } - - l_dbus_message_builder_finalize(builder); - - ret = strcmp(signature, builder->message->signature) == 0; - - l_dbus_message_builder_destroy(builder); - - return ret; -} - -LIB_EXPORT bool l_dbus_message_get_error(struct l_dbus_message *message, - const char **name, const char **text) -{ - struct dbus_header *hdr; - const char *str; - - if (unlikely(!message)) - return false; - - hdr = message->header; - - if (hdr->message_type != DBUS_MESSAGE_TYPE_ERROR) - return false; - - if (!message->signature) - return false; - - if (message->signature[0] != 's') - return false; - - str = _dbus_message_get_nth_string_argument(message, 0); - if (!str) - return false; - - if (!message->error_name) - get_header_field(message, DBUS_MESSAGE_FIELD_ERROR_NAME, 's', - &message->error_name); - - if (name) - *name = message->error_name; - - if (text) - *text = str; - - return true; -} - -LIB_EXPORT bool l_dbus_message_is_error(struct l_dbus_message *message) -{ - struct dbus_header *hdr; - - if (unlikely(!message)) - return false; - - hdr = message->header; - return hdr->message_type == DBUS_MESSAGE_TYPE_ERROR; -} - -LIB_EXPORT bool l_dbus_message_get_arguments_valist( - struct l_dbus_message *message, - const char *signature, va_list args) -{ - struct l_dbus_message_iter iter; - - if (unlikely(!message)) - return false; - - if (!message->signature) { - /* An empty signature is valid */ - if (!signature || *signature == '\0') - return true; - - return false; - } - - if (!signature || strcmp(message->signature, signature)) - return false; - - if (_dbus_message_is_gvariant(message)) { - if (!_gvariant_iter_init(&iter, message, message->signature, - NULL, message->body, - message->body_size)) - return false; - } else - _dbus1_iter_init(&iter, message, message->signature, NULL, - message->body, message->body_size); - - return message_iter_next_entry_valist(&iter, args); -} - -LIB_EXPORT bool l_dbus_message_get_arguments(struct l_dbus_message *message, - const char *signature, ...) -{ - va_list args; - bool result; - - va_start(args, signature); - result = l_dbus_message_get_arguments_valist(message, signature, args); - va_end(args); - - return result; -} - -LIB_EXPORT bool l_dbus_message_set_arguments(struct l_dbus_message *message, - const char *signature, ...) -{ - va_list args; - bool result; - - if (unlikely(!message)) - return false; - - if (unlikely(message->sealed)) - return false; - - if (!signature) - return true; - - va_start(args, signature); - result = append_arguments(message, signature, args); - va_end(args); - - return result; -} - -LIB_EXPORT bool l_dbus_message_set_arguments_valist( - struct l_dbus_message *message, - const char *signature, va_list args) -{ - bool result; - - if (unlikely(!message)) - return false; - - if (!signature) - return true; - - result = append_arguments(message, signature, args); - - return result; -} - -LIB_EXPORT const char *l_dbus_message_get_path(struct l_dbus_message *message) -{ - if (unlikely(!message)) - return NULL; - - if (!message->path && message->sealed) - get_header_field(message, DBUS_MESSAGE_FIELD_PATH, 'o', - &message->path); - - return message->path; -} - -LIB_EXPORT const char *l_dbus_message_get_interface(struct l_dbus_message *message) -{ - if (unlikely(!message)) - return NULL; - - if (!message->interface && message->sealed) - get_header_field(message, DBUS_MESSAGE_FIELD_INTERFACE, 's', - &message->interface); - - return message->interface; -} - -LIB_EXPORT const char *l_dbus_message_get_member(struct l_dbus_message *message) -{ - if (unlikely(!message)) - return NULL; - - if (!message->member && message->sealed) - get_header_field(message, DBUS_MESSAGE_FIELD_MEMBER, 's', - &message->member); - - return message->member; -} - -LIB_EXPORT const char *l_dbus_message_get_destination(struct l_dbus_message *message) -{ - if (unlikely(!message)) - return NULL; - - if (!message->destination && message->sealed) - get_header_field(message, DBUS_MESSAGE_FIELD_DESTINATION, 's', - &message->destination); - - return message->destination; -} - -LIB_EXPORT const char *l_dbus_message_get_sender(struct l_dbus_message *message) -{ - if (unlikely(!message)) - return NULL; - - if (!message->sender && message->sealed) - get_header_field(message, DBUS_MESSAGE_FIELD_SENDER, 's', - &message->sender); - - return message->sender; -} - -LIB_EXPORT const char *l_dbus_message_get_signature( - struct l_dbus_message *message) -{ - if (unlikely(!message)) - return NULL; - - return message->signature; -} - -uint32_t _dbus_message_get_reply_serial(struct l_dbus_message *message) -{ - if (unlikely(!message)) - return 0; - - if (message->reply_serial == 0 && message->sealed) { - if (_dbus_message_is_gvariant(message)) { - uint64_t reply_serial = 0; - - get_header_field(message, - DBUS_MESSAGE_FIELD_REPLY_SERIAL, 't', - &reply_serial); - - message->reply_serial = reply_serial; - } else - get_header_field(message, - DBUS_MESSAGE_FIELD_REPLY_SERIAL, 'u', - &message->reply_serial); - } - - return message->reply_serial; -} - -enum dbus_message_type _dbus_message_get_type(struct l_dbus_message *message) -{ - struct dbus_header *header; - - header = message->header; - return header->message_type; -} - -const char * _dbus_message_get_type_as_string(struct l_dbus_message *message) -{ - struct dbus_header *header; - - header = message->header; - - switch (header->message_type) { - case DBUS_MESSAGE_TYPE_METHOD_CALL: - return "method_call"; - case DBUS_MESSAGE_TYPE_METHOD_RETURN: - return "method_return"; - case DBUS_MESSAGE_TYPE_ERROR: - return "error"; - case DBUS_MESSAGE_TYPE_SIGNAL: - return "signal"; - } - - return NULL; -} - -uint8_t _dbus_message_get_endian(struct l_dbus_message *message) -{ - struct dbus_header *header = message->header; - - return header->endian; -} - -uint8_t _dbus_message_get_version(struct l_dbus_message *message) -{ - struct dbus_header *header = message->header; - - return header->version; -} - -LIB_EXPORT bool l_dbus_message_iter_next_entry(struct l_dbus_message_iter *iter, - ...) -{ - va_list args; - bool result; - - if (unlikely(!iter)) - return false; - - va_start(args, iter); - result = message_iter_next_entry_valist(iter, args); - va_end(args); - - return result; -} - -LIB_EXPORT bool l_dbus_message_iter_get_variant( - struct l_dbus_message_iter *iter, - const char *signature, ...) -{ - va_list args; - bool result; - - if (unlikely(!iter)) - return false; - - if (!iter->sig_start || strlen(signature) != iter->sig_len || - memcmp(iter->sig_start, signature, iter->sig_len)) - return false; - - va_start(args, signature); - result = message_iter_next_entry_valist(iter, args); - va_end(args); - - return result; -} - -LIB_EXPORT bool l_dbus_message_iter_get_fixed_array( - struct l_dbus_message_iter *iter, - void *out, uint32_t *n_elem) -{ - if (unlikely(!iter)) - return false; - - if (_dbus_message_is_gvariant(iter->message)) - return false; - - return _dbus1_iter_get_fixed_array(iter, out, n_elem); -} - -void _dbus_message_set_sender(struct l_dbus_message *message, - const char *sender) -{ - if (!_dbus_message_is_gvariant(message)) - return; - - l_free(message->sender); - - message->sender = l_strdup(sender); -} - -void _dbus_message_set_destination(struct l_dbus_message *message, - const char *destination) -{ - if (!_dbus_message_is_gvariant(message)) - return; - - l_free(message->destination); - - message->destination = l_strdup(destination); -} - -LIB_EXPORT struct l_dbus_message_builder *l_dbus_message_builder_new( - struct l_dbus_message *message) -{ - struct l_dbus_message_builder *ret; - - if (unlikely(!message)) - return NULL; - - if (message->sealed) - return NULL; - - ret = l_new(struct l_dbus_message_builder, 1); - ret->message = l_dbus_message_ref(message); - - if (_dbus_message_is_gvariant(message)) - ret->driver = &gvariant_driver; - else - ret->driver = &dbus1_driver; - - ret->builder = ret->driver->new(NULL, 0); - - return ret; -} - -LIB_EXPORT void l_dbus_message_builder_destroy( - struct l_dbus_message_builder *builder) -{ - if (unlikely(!builder)) - return; - - builder->driver->free(builder->builder); - l_dbus_message_unref(builder->message); - - l_free(builder); -} - -LIB_EXPORT bool l_dbus_message_builder_append_basic( - struct l_dbus_message_builder *builder, - char type, const void *value) -{ - if (unlikely(!builder)) - return false; - - return builder->driver->append_basic(builder->builder, type, value); -} - -LIB_EXPORT bool l_dbus_message_builder_enter_container( - struct l_dbus_message_builder *builder, - char container_type, - const char *signature) -{ - if (unlikely(!builder)) - return false; - - switch (container_type) { - case DBUS_CONTAINER_TYPE_ARRAY: - return builder->driver->enter_array(builder->builder, - signature); - case DBUS_CONTAINER_TYPE_DICT_ENTRY: - return builder->driver->enter_dict(builder->builder, signature); - case DBUS_CONTAINER_TYPE_STRUCT: - return builder->driver->enter_struct(builder->builder, - signature); - case DBUS_CONTAINER_TYPE_VARIANT: - return builder->driver->enter_variant(builder->builder, - signature); - default: - break; - } - - return false; -} - -LIB_EXPORT bool l_dbus_message_builder_leave_container( - struct l_dbus_message_builder *builder, - char container_type) -{ - if (unlikely(!builder)) - return false; - - switch (container_type) { - case DBUS_CONTAINER_TYPE_ARRAY: - return builder->driver->leave_array(builder->builder); - case DBUS_CONTAINER_TYPE_DICT_ENTRY: - return builder->driver->leave_dict(builder->builder); - case DBUS_CONTAINER_TYPE_STRUCT: - return builder->driver->leave_struct(builder->builder); - case DBUS_CONTAINER_TYPE_VARIANT: - return builder->driver->leave_variant(builder->builder); - default: - break; - } - - return false; -} - -LIB_EXPORT bool l_dbus_message_builder_enter_struct( - struct l_dbus_message_builder *builder, - const char *signature) -{ - return l_dbus_message_builder_enter_container(builder, 'r', signature); -} - -LIB_EXPORT bool l_dbus_message_builder_leave_struct( - struct l_dbus_message_builder *builder) -{ - return l_dbus_message_builder_leave_container(builder, 'r'); -} - -LIB_EXPORT bool l_dbus_message_builder_enter_array( - struct l_dbus_message_builder *builder, - const char *signature) -{ - return l_dbus_message_builder_enter_container(builder, 'a', signature); -} - -LIB_EXPORT bool l_dbus_message_builder_leave_array( - struct l_dbus_message_builder *builder) -{ - return l_dbus_message_builder_leave_container(builder, 'a'); -} - -LIB_EXPORT bool l_dbus_message_builder_enter_dict( - struct l_dbus_message_builder *builder, - const char *signature) -{ - return l_dbus_message_builder_enter_container(builder, 'e', signature); -} - -LIB_EXPORT bool l_dbus_message_builder_leave_dict( - struct l_dbus_message_builder *builder) -{ - return l_dbus_message_builder_leave_container(builder, 'e'); -} - -LIB_EXPORT bool l_dbus_message_builder_enter_variant( - struct l_dbus_message_builder *builder, - const char *signature) -{ - return l_dbus_message_builder_enter_container(builder, 'v', signature); -} - -LIB_EXPORT bool l_dbus_message_builder_leave_variant( - struct l_dbus_message_builder *builder) -{ - return l_dbus_message_builder_leave_container(builder, 'v'); -} - -/** - * l_dbus_message_builder_append_from_iter: - * @builder: message builder to receive a new value - * @from: message iterator to have its position moved by one value - * - * Copy one value from a message iterator onto a message builder. The - * value's signature is also copied. - * - * Returns: whether the value was correctly copied. On failure both - * the @from iterator and the @builder may have their positions - * moved to somewhere within the new value if it's of a - * container type. - **/ -LIB_EXPORT bool l_dbus_message_builder_append_from_iter( - struct l_dbus_message_builder *builder, - struct l_dbus_message_iter *from) -{ - static const char *simple_types = "sogybnqiuxtd"; - char type = from->sig_start[from->sig_pos]; - char container_type; - char signature[256]; - struct l_dbus_message_iter iter; - void *basic_ptr; - uint64_t basic; - uint32_t uint32_val; - bool (*get_basic)(struct l_dbus_message_iter *, char, void *); - bool (*enter_func)(struct l_dbus_message_iter *, - struct l_dbus_message_iter *); - bool (*enter_struct)(struct l_dbus_message_iter *, - struct l_dbus_message_iter *); - bool (*enter_array)(struct l_dbus_message_iter *, - struct l_dbus_message_iter *); - bool (*enter_variant)(struct l_dbus_message_iter *, - struct l_dbus_message_iter *); - - if (_dbus_message_is_gvariant(from->message)) { - get_basic = _gvariant_iter_next_entry_basic; - enter_struct = _gvariant_iter_enter_struct; - enter_array = _gvariant_iter_enter_array; - enter_variant = _gvariant_iter_enter_variant; - } else { - get_basic = _dbus1_iter_next_entry_basic; - enter_struct = _dbus1_iter_enter_struct; - enter_array = _dbus1_iter_enter_array; - enter_variant = _dbus1_iter_enter_variant; - } - - if (strchr(simple_types, type)) { - if (strchr("sog", type)) { - if (!get_basic(from, type, &basic_ptr)) - return false; - } else { - basic_ptr = &basic; - - if (!get_basic(from, type, basic_ptr)) - return false; - } - - if (!l_dbus_message_builder_append_basic(builder, type, - basic_ptr)) - return false; - - return true; - } - - switch (type) { - case 'h': - if (!get_basic(from, type, &uint32_val)) - return false; - - if (!l_dbus_message_builder_append_basic(builder, type, - &builder->message->num_fds)) - return false; - - if (builder->message->num_fds < - L_ARRAY_SIZE(builder->message->fds)) { - int fd; - - if (uint32_val < from->message->num_fds) - fd = fcntl(from->message->fds[uint32_val], - F_DUPFD_CLOEXEC, 3); - else - fd = -1; - - builder->message->fds[builder->message->num_fds++] = fd; - } - - return true; - case '(': - enter_func = enter_struct; - container_type = DBUS_CONTAINER_TYPE_STRUCT; - break; - case '{': - enter_func = enter_struct; - container_type = DBUS_CONTAINER_TYPE_DICT_ENTRY; - break; - case 'a': - enter_func = enter_array; - container_type = DBUS_CONTAINER_TYPE_ARRAY; - break; - case 'v': - enter_func = enter_variant; - container_type = DBUS_CONTAINER_TYPE_VARIANT; - break; - default: - return false; - } - - if (!enter_func(from, &iter)) - return false; - - memcpy(signature, iter.sig_start, iter.sig_len); - signature[iter.sig_len] = '\0'; - - if (!l_dbus_message_builder_enter_container(builder, - container_type, signature)) - return false; - - if (container_type == DBUS_CONTAINER_TYPE_ARRAY) - while(l_dbus_message_builder_append_from_iter(builder, &iter)); - else - while (iter.sig_pos < iter.sig_len) - if (!l_dbus_message_builder_append_from_iter(builder, - &iter)) - return false; - - if (!l_dbus_message_builder_leave_container(builder, - container_type)) - return false; - - return true; -} - -LIB_EXPORT bool l_dbus_message_builder_append_from_valist( - struct l_dbus_message_builder *builder, - const char *signature, va_list args) -{ - struct builder_driver *driver; - char subsig[256]; - const char *sigend; - /* Nesting requires an extra stack entry for the base level */ - struct container stack[DBUS_MAX_NESTING + 1]; - unsigned int stack_index = 0; - - if (unlikely(!builder)) - return false; - - driver = builder->driver; - - stack[stack_index].type = DBUS_CONTAINER_TYPE_STRUCT; - stack[stack_index].sig_start = signature; - stack[stack_index].sig_end = signature + strlen(signature); - stack[stack_index].n_items = 0; - - while (stack_index != 0 || stack[0].sig_start != stack[0].sig_end) { - const char *s; - const char *str; - - if (stack[stack_index].type == DBUS_CONTAINER_TYPE_ARRAY && - stack[stack_index].n_items == 0) - stack[stack_index].sig_start = - stack[stack_index].sig_end; - - if (stack[stack_index].sig_start == - stack[stack_index].sig_end) { - bool ret; - - /* - * Sanity check in case of an invalid signature that - * isn't caught elsewhere. - */ - if (unlikely(stack_index == 0)) - return false; - - switch (stack[stack_index].type) { - case DBUS_CONTAINER_TYPE_STRUCT: - ret = driver->leave_struct(builder->builder); - break; - case DBUS_CONTAINER_TYPE_DICT_ENTRY: - ret = driver->leave_dict(builder->builder); - break; - case DBUS_CONTAINER_TYPE_VARIANT: - ret = driver->leave_variant(builder->builder); - break; - case DBUS_CONTAINER_TYPE_ARRAY: - ret = driver->leave_array(builder->builder); - break; - default: - ret = false; - } - - if (!ret) - return false; - - stack_index -= 1; - continue; - } - - s = stack[stack_index].sig_start; - - if (stack[stack_index].type != DBUS_CONTAINER_TYPE_ARRAY) - stack[stack_index].sig_start += 1; - else - stack[stack_index].n_items -= 1; - - switch (*s) { - case 'o': - case 's': - case 'g': - str = va_arg(args, const char *); - - if (!driver->append_basic(builder->builder, *s, str)) - return false; - break; - case 'b': - case 'y': - { - uint8_t y = (uint8_t) va_arg(args, int); - - if (!driver->append_basic(builder->builder, *s, &y)) - return false; - - break; - } - case 'n': - case 'q': - { - uint16_t n = (uint16_t) va_arg(args, int); - - if (!driver->append_basic(builder->builder, *s, &n)) - return false; - - break; - } - case 'i': - case 'u': - { - uint32_t u = va_arg(args, uint32_t); - - if (!driver->append_basic(builder->builder, *s, &u)) - return false; - - break; - } - case 'h': - { - int fd = va_arg(args, int); - struct l_dbus_message *message = builder->message; - - if (!driver->append_basic(builder->builder, *s, - &message->num_fds)) - return false; - - if (message->num_fds < L_ARRAY_SIZE(message->fds)) - message->fds[message->num_fds++] = - fcntl(fd, F_DUPFD_CLOEXEC, 3); - - break; - } - case 'x': - case 't': - { - uint64_t x = va_arg(args, uint64_t); - - if (!driver->append_basic(builder->builder, *s, &x)) - return false; - break; - } - case 'd': - { - double d = va_arg(args, double); - - if (!driver->append_basic(builder->builder, *s, &d)) - return false; - break; - } - case '(': - case '{': - if (stack_index == DBUS_MAX_NESTING) - return false; - - sigend = _dbus_signature_end(s); - memcpy(subsig, s + 1, sigend - s - 1); - subsig[sigend - s - 1] = '\0'; - - if (*s == '(' && !driver->enter_struct(builder->builder, - subsig)) - return false; - - if (*s == '{' && !driver->enter_dict(builder->builder, - subsig)) - return false; - - if (stack[stack_index].type != - DBUS_CONTAINER_TYPE_ARRAY) - stack[stack_index].sig_start = sigend + 1; - - stack_index += 1; - stack[stack_index].sig_start = s + 1; - stack[stack_index].sig_end = sigend; - stack[stack_index].n_items = 0; - stack[stack_index].type = *s == '(' ? - DBUS_CONTAINER_TYPE_STRUCT : - DBUS_CONTAINER_TYPE_DICT_ENTRY; - - break; - case 'v': - if (stack_index == DBUS_MAX_NESTING) - return false; - - str = va_arg(args, const char *); - - if (!str) - return false; - - if (!driver->enter_variant(builder->builder, str)) - return false; - - stack_index += 1; - stack[stack_index].type = DBUS_CONTAINER_TYPE_VARIANT; - stack[stack_index].sig_start = str; - stack[stack_index].sig_end = str + strlen(str); - stack[stack_index].n_items = 0; - - break; - case 'a': - if (stack_index == DBUS_MAX_NESTING) - return false; - - sigend = _dbus_signature_end(s + 1) + 1; - memcpy(subsig, s + 1, sigend - s - 1); - subsig[sigend - s - 1] = '\0'; - - if (!driver->enter_array(builder->builder, subsig)) - return false; - - if (stack[stack_index].type != - DBUS_CONTAINER_TYPE_ARRAY) - stack[stack_index].sig_start = sigend; - - stack_index += 1; - stack[stack_index].sig_start = s + 1; - stack[stack_index].sig_end = sigend; - stack[stack_index].n_items = va_arg(args, unsigned int); - stack[stack_index].type = DBUS_CONTAINER_TYPE_ARRAY; - - break; - default: - return false; - } - } - - return true; -} - -LIB_EXPORT struct l_dbus_message *l_dbus_message_builder_finalize( - struct l_dbus_message_builder *builder) -{ - char *generated_signature; - - if (unlikely(!builder)) - return NULL; - - generated_signature = builder->driver->finish(builder->builder, - &builder->message->body, - &builder->message->body_size); - - build_header(builder->message, generated_signature); - builder->message->sealed = true; - builder->message->signature = generated_signature; - builder->message->signature_free = true; - - return builder->message; -} - -bool _dbus_message_builder_mark(struct l_dbus_message_builder *builder) -{ - if (unlikely(!builder)) - return false; - - return builder->driver->mark(builder->builder); -} - -bool _dbus_message_builder_rewind(struct l_dbus_message_builder *builder) -{ - if (unlikely(!builder)) - return false; - - return builder->driver->rewind(builder->builder); -} diff --git a/ell/dbus-name-cache.c b/ell/dbus-name-cache.c deleted file mode 100644 index fdc5b18..0000000 --- a/ell/dbus-name-cache.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2016 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include - -#include "util.h" -#include "hashmap.h" -#include "idle.h" -#include "dbus.h" -#include "dbus-private.h" - -struct _dbus_name_cache { - struct l_dbus *bus; - struct l_hashmap *names; - const struct _dbus_name_ops *driver; - unsigned int last_watch_id; - struct l_idle *watch_remove_work; -}; - -struct service_watch { - l_dbus_watch_func_t connect_func; - l_dbus_watch_func_t disconnect_func; - l_dbus_destroy_func_t destroy; - void *user_data; - unsigned int id; - bool removed; - struct service_watch *next; -}; - -struct name_cache_entry { - int ref_count; - char *unique_name; - struct service_watch *watches; -}; - -struct _dbus_name_cache *_dbus_name_cache_new(struct l_dbus *bus, - const struct _dbus_name_ops *driver) -{ - struct _dbus_name_cache *cache; - - cache = l_new(struct _dbus_name_cache, 1); - - cache->bus = bus; - cache->driver = driver; - - return cache; -} - -static void service_watch_destroy(void *data) -{ - struct service_watch *watch = data; - - if (watch->destroy) - watch->destroy(watch->user_data); - - l_free(watch); -} - -static void name_cache_entry_destroy(void *data) -{ - struct name_cache_entry *entry = data; - struct service_watch *watch; - - while (entry->watches) { - watch = entry->watches; - entry->watches = watch->next; - - service_watch_destroy(watch); - } - - l_free(entry->unique_name); - - l_free(entry); -} - -void _dbus_name_cache_free(struct _dbus_name_cache *cache) -{ - if (!cache) - return; - - if (cache->watch_remove_work) - l_idle_remove(cache->watch_remove_work); - - l_hashmap_destroy(cache->names, name_cache_entry_destroy); - - l_free(cache); -} - -bool _dbus_name_cache_add(struct _dbus_name_cache *cache, const char *name) -{ - struct name_cache_entry *entry; - - if (!_dbus_valid_bus_name(name)) - return false; - - if (!cache->names) - cache->names = l_hashmap_string_new(); - - entry = l_hashmap_lookup(cache->names, name); - - if (!entry) { - entry = l_new(struct name_cache_entry, 1); - - l_hashmap_insert(cache->names, name, entry); - - cache->driver->get_name_owner(cache->bus, name); - } - - entry->ref_count++; - - return true; -} - -bool _dbus_name_cache_remove(struct _dbus_name_cache *cache, const char *name) -{ - struct name_cache_entry *entry; - - entry = l_hashmap_lookup(cache->names, name); - - if (!entry) - return false; - - if (--entry->ref_count) - return true; - - l_hashmap_remove(cache->names, name); - - name_cache_entry_destroy(entry); - - return true; -} - -const char *_dbus_name_cache_lookup(struct _dbus_name_cache *cache, - const char *name) -{ - struct name_cache_entry *entry; - - entry = l_hashmap_lookup(cache->names, name); - - if (!entry) - return NULL; - - return entry->unique_name; -} - -void _dbus_name_cache_notify(struct _dbus_name_cache *cache, - const char *name, const char *owner) -{ - struct name_cache_entry *entry; - struct service_watch *watch; - bool prev_connected, connected; - - if (!cache) - return; - - entry = l_hashmap_lookup(cache->names, name); - - if (!entry) - return; - - prev_connected = !!entry->unique_name; - connected = owner && *owner != '\0'; - - l_free(entry->unique_name); - - entry->unique_name = connected ? l_strdup(owner) : NULL; - - /* - * This check also means we notify all watchers who have a connected - * callback when we first learn that the service is in fact connected. - */ - if (connected == prev_connected) - return; - - for (watch = entry->watches; watch; watch = watch->next) - if (connected && watch->connect_func) - watch->connect_func(cache->bus, watch->user_data); - else if (!connected && watch->disconnect_func) - watch->disconnect_func(cache->bus, watch->user_data); -} - -unsigned int _dbus_name_cache_add_watch(struct _dbus_name_cache *cache, - const char *name, - l_dbus_watch_func_t connect_func, - l_dbus_watch_func_t disconnect_func, - void *user_data, - l_dbus_destroy_func_t destroy) -{ - struct name_cache_entry *entry; - struct service_watch *watch; - - if (!_dbus_name_cache_add(cache, name)) - return 0; - - watch = l_new(struct service_watch, 1); - watch->id = ++cache->last_watch_id; - watch->connect_func = connect_func; - watch->disconnect_func = disconnect_func; - watch->user_data = user_data; - watch->destroy = destroy; - - entry = l_hashmap_lookup(cache->names, name); - - watch->next = entry->watches; - entry->watches = watch; - - if (entry->unique_name && connect_func) - watch->connect_func(cache->bus, watch->user_data); - - return watch->id; -} - -static bool service_watch_remove(const void *key, void *value, void *user_data) -{ - struct name_cache_entry *entry = value; - struct service_watch **watch, *tmp; - - for (watch = &entry->watches; *watch;) { - if (!(*watch)->removed) { - watch = &(*watch)->next; - continue; - } - - tmp = *watch; - *watch = tmp->next; - - service_watch_destroy(tmp); - - entry->ref_count--; - } - - if (entry->ref_count) - return false; - - name_cache_entry_destroy(entry); - - return true; -} - -static void service_watch_remove_all(struct l_idle *idle, void *user_data) -{ - struct _dbus_name_cache *cache = user_data; - - l_idle_remove(cache->watch_remove_work); - cache->watch_remove_work = NULL; - - l_hashmap_foreach_remove(cache->names, service_watch_remove, cache); -} - -static void service_watch_mark(const void *key, void *value, void *user_data) -{ - struct name_cache_entry *entry = value; - struct service_watch *watch; - unsigned int *id = user_data; - - for (watch = entry->watches; watch; watch = watch->next) - if (watch->id == *id) { - watch->removed = true; - watch->connect_func = NULL; - watch->disconnect_func = NULL; - *id = 0; - break; - } -} - -bool _dbus_name_cache_remove_watch(struct _dbus_name_cache *cache, - unsigned int id) -{ - l_hashmap_foreach(cache->names, service_watch_mark, &id); - - if (id) - return false; - - if (!cache->watch_remove_work) - cache->watch_remove_work = l_idle_create( - service_watch_remove_all, - cache, NULL); - - return true; -} diff --git a/ell/dbus-private.h b/ell/dbus-private.h deleted file mode 100644 index be62691..0000000 --- a/ell/dbus-private.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include - -enum dbus_message_type { - DBUS_MESSAGE_TYPE_METHOD_CALL = 1, - DBUS_MESSAGE_TYPE_METHOD_RETURN = 2, - DBUS_MESSAGE_TYPE_ERROR = 3, - DBUS_MESSAGE_TYPE_SIGNAL = 4, -}; - -enum dbus_container_type { - DBUS_CONTAINER_TYPE_ARRAY = 'a', - DBUS_CONTAINER_TYPE_STRUCT = 'r', - DBUS_CONTAINER_TYPE_VARIANT = 'v', - DBUS_CONTAINER_TYPE_DICT_ENTRY = 'e', -}; - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define DBUS_NATIVE_ENDIAN 'l' -#elif __BYTE_ORDER == __BIG_ENDIAN -#define DBUS_NATIVE_ENDIAN 'B' -#else -#error "Unknown byte order" -#endif - -struct dbus_header { - uint8_t endian; - uint8_t message_type; - uint8_t flags; - uint8_t version; - - union { - struct { - uint32_t body_length; - uint32_t serial; - uint32_t field_length; - } __attribute__ ((packed)) dbus1; - }; -} __attribute__ ((packed)); -#define DBUS_HEADER_SIZE 16 - -struct dbus_builder; -struct l_string; -struct l_dbus_interface; -struct _dbus_method; -struct _dbus_signal; -struct _dbus_property; -struct l_dbus_message_iter; -struct l_dbus_message; -struct l_dbus; -struct _dbus_filter; -struct _dbus_filter_condition; -struct _dbus_filter_ops; - -void _dbus1_iter_init(struct l_dbus_message_iter *iter, - struct l_dbus_message *message, - const char *sig_start, const char *sig_end, - const void *data, size_t len); -bool _dbus1_iter_next_entry_basic(struct l_dbus_message_iter *iter, char type, - void *out); -bool _dbus1_iter_get_fixed_array(struct l_dbus_message_iter *iter, - void *out, uint32_t *n_elem); -bool _dbus1_iter_enter_struct(struct l_dbus_message_iter *iter, - struct l_dbus_message_iter *structure); -bool _dbus1_iter_enter_variant(struct l_dbus_message_iter *iter, - struct l_dbus_message_iter *variant); -bool _dbus1_iter_enter_array(struct l_dbus_message_iter *iter, - struct l_dbus_message_iter *array); -bool _dbus1_iter_skip_entry(struct l_dbus_message_iter *iter); - -struct dbus_builder *_dbus1_builder_new(void *body, size_t body_size); -void _dbus1_builder_free(struct dbus_builder *builder); -bool _dbus1_builder_append_basic(struct dbus_builder *builder, - char type, const void *value); -bool _dbus1_builder_enter_struct(struct dbus_builder *builder, - const char *signature); -bool _dbus1_builder_leave_struct(struct dbus_builder *builder); -bool _dbus1_builder_enter_dict(struct dbus_builder *builder, - const char *signature); -bool _dbus1_builder_leave_dict(struct dbus_builder *builder); -bool _dbus1_builder_enter_variant(struct dbus_builder *builder, - const char *signature); -bool _dbus1_builder_leave_variant(struct dbus_builder *builder); -bool _dbus1_builder_enter_array(struct dbus_builder *builder, - const char *signature); -bool _dbus1_builder_leave_array(struct dbus_builder *builder); -char *_dbus1_builder_finish(struct dbus_builder *builder, - void **body, size_t *body_size); -bool _dbus1_builder_mark(struct dbus_builder *builder); -bool _dbus1_builder_rewind(struct dbus_builder *builder); - -void *_dbus_message_get_body(struct l_dbus_message *msg, size_t *out_size); -void *_dbus_message_get_header(struct l_dbus_message *msg, size_t *out_size); -void *_dbus_message_get_footer(struct l_dbus_message *msg, size_t *out_size); -int *_dbus_message_get_fds(struct l_dbus_message *msg, uint32_t *num_fds); -void _dbus_message_set_serial(struct l_dbus_message *msg, uint32_t serial); -uint32_t _dbus_message_get_serial(struct l_dbus_message *msg); -uint32_t _dbus_message_get_reply_serial(struct l_dbus_message *message); - -void _dbus_message_set_sender(struct l_dbus_message *message, - const char *sender); -void _dbus_message_set_destination(struct l_dbus_message *message, - const char *destination); - -enum dbus_message_type _dbus_message_get_type(struct l_dbus_message *message); -const char * _dbus_message_get_type_as_string(struct l_dbus_message *message); -uint8_t _dbus_message_get_version(struct l_dbus_message *message); -uint8_t _dbus_message_get_endian(struct l_dbus_message *message); -const char *_dbus_message_get_nth_string_argument( - struct l_dbus_message *message, int n); - -struct l_dbus_message *_dbus_message_new_method_call(uint8_t version, - const char *destination, - const char *path, - const char *interface, - const char *method); -struct l_dbus_message *_dbus_message_new_signal(uint8_t version, - const char *path, - const char *interface, - const char *name); -struct l_dbus_message *_dbus_message_new_error(uint8_t version, - uint32_t reply_serial, - const char *destination, - const char *name, - const char *error); - -struct l_dbus_message *dbus_message_from_blob(const void *data, size_t size, - int fds[], uint32_t num_fds); -struct l_dbus_message *dbus_message_build(void *header, size_t header_size, - void *body, size_t body_size, - int fds[], uint32_t num_fds); -bool dbus_message_compare(struct l_dbus_message *message, - const void *data, size_t size); - -bool _dbus_message_builder_mark(struct l_dbus_message_builder *builder); -bool _dbus_message_builder_rewind(struct l_dbus_message_builder *builder); - -unsigned int _dbus_message_unix_fds_from_header(const void *data, size_t size); - -const char *_dbus_signature_end(const char *signature); - -bool _dbus_valid_object_path(const char *path); -bool _dbus_valid_signature(const char *sig); -int _dbus_num_children(const char *sig); -bool _dbus_valid_interface(const char *interface); -bool _dbus_valid_method(const char *method); -bool _dbus_parse_unique_name(const char *name, uint64_t *out_id); -bool _dbus_valid_bus_name(const char *bus_name); - -bool _dbus1_header_is_valid(void *data, size_t size); - -void _dbus_method_introspection(struct _dbus_method *info, - struct l_string *buf); -void _dbus_signal_introspection(struct _dbus_signal *info, - struct l_string *buf); -void _dbus_property_introspection(struct _dbus_property *info, - struct l_string *buf); -void _dbus_interface_introspection(struct l_dbus_interface *interface, - struct l_string *buf); - -struct l_dbus_interface *_dbus_interface_new(const char *interface); -void _dbus_interface_free(struct l_dbus_interface *interface); - -struct _dbus_method *_dbus_interface_find_method(struct l_dbus_interface *i, - const char *method); -struct _dbus_signal *_dbus_interface_find_signal(struct l_dbus_interface *i, - const char *signal); -struct _dbus_property *_dbus_interface_find_property(struct l_dbus_interface *i, - const char *property); - -struct _dbus_object_tree *_dbus_object_tree_new(); -void _dbus_object_tree_free(struct _dbus_object_tree *tree); - -struct object_node *_dbus_object_tree_makepath(struct _dbus_object_tree *tree, - const char *path); -struct object_node *_dbus_object_tree_lookup(struct _dbus_object_tree *tree, - const char *path); -void _dbus_object_tree_prune_node(struct object_node *node); - -struct object_node *_dbus_object_tree_new_object(struct _dbus_object_tree *tree, - const char *path, - void *user_data, - void (*destroy) (void *)); -bool _dbus_object_tree_object_destroy(struct _dbus_object_tree *tree, - const char *path); - -bool _dbus_object_tree_register_interface(struct _dbus_object_tree *tree, - const char *interface, - void (*setup_func)(struct l_dbus_interface *), - void (*destroy) (void *), - bool old_style_properties); -bool _dbus_object_tree_unregister_interface(struct _dbus_object_tree *tree, - const char *interface); - -bool _dbus_object_tree_add_interface(struct _dbus_object_tree *tree, - const char *path, const char *interface, - void *user_data); -bool _dbus_object_tree_remove_interface(struct _dbus_object_tree *tree, - const char *path, - const char *interface); -void *_dbus_object_tree_get_interface_data(struct _dbus_object_tree *tree, - const char *path, - const char *interface); - -void _dbus_object_tree_introspect(struct _dbus_object_tree *tree, - const char *path, struct l_string *buf); -bool _dbus_object_tree_dispatch(struct _dbus_object_tree *tree, - struct l_dbus *dbus, - struct l_dbus_message *message); -struct l_dbus_message *_dbus_object_tree_get_objects( - struct _dbus_object_tree *tree, - struct l_dbus *dbus, - const char *path, - struct l_dbus_message *message); - -bool _dbus_object_tree_property_changed(struct l_dbus *dbus, - const char *path, - const char *interface_name, - const char *property_name); - -void _dbus_object_tree_signals_flush(struct l_dbus *dbus, const char *path); - -typedef void (*_dbus_name_owner_change_func_t)(const char *name, - uint64_t old_owner, - uint64_t new_owner, - void *user_data); - -uint8_t _dbus_get_version(struct l_dbus *dbus); -int _dbus_get_fd(struct l_dbus *dbus); -struct _dbus_object_tree *_dbus_get_tree(struct l_dbus *dbus); - -struct _dbus_name_ops { - bool (*get_name_owner)(struct l_dbus *bus, const char *name); -}; - -struct _dbus_name_cache; - -struct _dbus_name_cache *_dbus_name_cache_new(struct l_dbus *bus, - const struct _dbus_name_ops *driver); -void _dbus_name_cache_free(struct _dbus_name_cache *cache); - -bool _dbus_name_cache_add(struct _dbus_name_cache *cache, const char *name); -bool _dbus_name_cache_remove(struct _dbus_name_cache *cache, const char *name); -const char *_dbus_name_cache_lookup(struct _dbus_name_cache *cache, - const char *name); - -void _dbus_name_cache_notify(struct _dbus_name_cache *cache, - const char *name, const char *owner); - -unsigned int _dbus_name_cache_add_watch(struct _dbus_name_cache *cache, - const char *name, - l_dbus_watch_func_t connect_func, - l_dbus_watch_func_t disconnect_func, - void *user_data, - l_dbus_destroy_func_t destroy); -bool _dbus_name_cache_remove_watch(struct _dbus_name_cache *cache, - unsigned int id); - -struct _dbus_filter_condition { - enum l_dbus_match_type type; - const char *value; -}; - -struct _dbus_filter_ops { - bool skip_register; - bool (*add_match)(struct l_dbus *bus, unsigned int id, - const struct _dbus_filter_condition *rule, - int rule_len); - bool (*remove_match)(struct l_dbus *bus, unsigned int id); -}; - -struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus, - const struct _dbus_filter_ops *driver, - struct _dbus_name_cache *name_cache); -void _dbus_filter_free(struct _dbus_filter *filter); - -unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter, - const struct _dbus_filter_condition *rule, - int rule_len, - l_dbus_message_func_t signal_func, - void *user_data); -bool _dbus_filter_remove_rule(struct _dbus_filter *filter, unsigned int id); - -char *_dbus_filter_rule_to_str(const struct _dbus_filter_condition *rule, - int rule_len); - -void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data); diff --git a/ell/dbus-service.c b/ell/dbus-service.c deleted file mode 100644 index d8e29e1..0000000 --- a/ell/dbus-service.c +++ /dev/null @@ -1,2102 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include - -#include "util.h" -#include "queue.h" -#include "string.h" -#include "hashmap.h" -#include "dbus.h" -#include "dbus-service.h" -#include "dbus-private.h" -#include "private.h" -#include "idle.h" - -#define XML_ID "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" -#define XML_DTD "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" -#define XML_HEAD "\n" - -static const char *static_introspectable = - "\t\n" - "\t\t\n" - "\t\t\t\n" - "\t\t\n\t\n"; - -struct _dbus_method { - l_dbus_interface_method_cb_t cb; - uint32_t flags; - unsigned char name_len; - char metainfo[]; -}; - -struct _dbus_signal { - uint32_t flags; - unsigned char name_len; - char metainfo[]; -}; - -struct _dbus_property { - l_dbus_property_get_cb_t getter; - l_dbus_property_set_cb_t setter; - uint32_t flags; - unsigned char name_len; - char metainfo[]; -}; - -struct l_dbus_interface { - struct l_queue *methods; - struct l_queue *signals; - struct l_queue *properties; - bool handle_old_style_properties; - void (*instance_destroy)(void *); - char name[]; -}; - -struct child_node { - struct object_node *node; - struct child_node *next; - char subpath[]; -}; - -struct interface_instance { - struct l_dbus_interface *interface; - void *user_data; -}; - -struct object_node { - struct object_node *parent; - struct l_queue *instances; - struct child_node *children; - void *user_data; - void (*destroy) (void *); -}; - -struct object_manager { - char *path; - struct l_dbus *dbus; - struct l_queue *announce_added; - struct l_queue *announce_removed; -}; - -struct interface_add_record { - char *path; - struct object_node *object; - struct l_queue *instances; -}; - -struct interface_remove_record { - char *path; - struct object_node *object; - struct l_queue *interface_names; -}; - -struct property_change_record { - char *path; - struct object_node *object; - struct interface_instance *instance; - struct l_queue *properties; -}; - -struct _dbus_object_tree { - struct l_hashmap *interfaces; - struct l_hashmap *objects; - struct object_node *root; - struct l_queue *object_managers; - struct l_queue *property_changes; - struct l_idle *emit_signals_work; - bool flushing; -}; - -void _dbus_method_introspection(struct _dbus_method *info, - struct l_string *buf) -{ - const char *sig; - const char *end; - const char *pname; - unsigned int offset = info->name_len + 1; - - l_string_append_printf(buf, "\t\t\n", - info->metainfo); - - sig = info->metainfo + offset; - offset += strlen(sig) + 1; - - for (; *sig; sig++) { - end = _dbus_signature_end(sig); - pname = info->metainfo + offset; - - l_string_append_printf(buf, "\t\t\t\n", - pname, (int) (end - sig + 1), sig); - sig = end; - offset += strlen(pname) + 1; - } - - sig = info->metainfo + offset; - offset += strlen(sig) + 1; - - for (; *sig; sig++) { - end = _dbus_signature_end(sig); - pname = info->metainfo + offset; - - l_string_append_printf(buf, "\t\t\t\n", - pname, (int) (end - sig + 1), sig); - sig = end; - offset += strlen(pname) + 1; - } - - if (info->flags & L_DBUS_METHOD_FLAG_DEPRECATED) - l_string_append(buf, "\t\t\t\n"); - - if (info->flags & L_DBUS_METHOD_FLAG_NOREPLY) - l_string_append(buf, "\t\t\t\n"); - - l_string_append(buf, "\t\t\n"); -} - -void _dbus_signal_introspection(struct _dbus_signal *info, - struct l_string *buf) -{ - const char *sig; - const char *end; - const char *pname; - unsigned int offset = info->name_len + 1; - - l_string_append_printf(buf, "\t\t\n", - info->metainfo); - - sig = info->metainfo + offset; - offset += strlen(sig) + 1; - - for (; *sig; sig++) { - end = _dbus_signature_end(sig); - pname = info->metainfo + offset; - - l_string_append_printf(buf, "\t\t\t\n", - pname, (int) (end - sig + 1), sig); - sig = end; - offset += strlen(pname) + 1; - } - - if (info->flags & L_DBUS_SIGNAL_FLAG_DEPRECATED) - l_string_append(buf, "\t\t\t\n"); - - l_string_append(buf, "\t\t\n"); -} - -void _dbus_property_introspection(struct _dbus_property *info, - struct l_string *buf) -{ - unsigned int offset = info->name_len + 1; - const char *signature = info->metainfo + offset; - - l_string_append_printf(buf, "\t\tmetainfo, signature); - - if (info->setter) - l_string_append(buf, "access=\"readwrite\""); - else - l_string_append(buf, "access=\"read\""); - - if (info->flags & L_DBUS_METHOD_FLAG_DEPRECATED) { - l_string_append(buf, ">\n"); - l_string_append(buf, "\t\t\t\n"); - l_string_append(buf, "\t\t\n"); - } else - l_string_append(buf, "/>\n"); -} - -void _dbus_interface_introspection(struct l_dbus_interface *interface, - struct l_string *buf) -{ - l_string_append_printf(buf, "\t\n", - interface->name); - - l_queue_foreach(interface->methods, - (l_queue_foreach_func_t) _dbus_method_introspection, buf); - l_queue_foreach(interface->signals, - (l_queue_foreach_func_t) _dbus_signal_introspection, buf); - l_queue_foreach(interface->properties, - (l_queue_foreach_func_t) _dbus_property_introspection, buf); - - l_string_append(buf, "\t\n"); -} - -#define COPY_PARAMS(dest, signature, args) \ - do { \ - const char *pname; \ - const char *sig; \ - dest = stpcpy(dest, signature) + 1; \ - for (sig = signature; *sig; sig++) { \ - sig = _dbus_signature_end(sig); \ - pname = va_arg(args, const char *); \ - dest = stpcpy(dest, pname) + 1; \ - } \ - } while(0) - -#define SIZE_PARAMS(signature, args) \ - ({ \ - unsigned int len = strlen(signature) + 1; \ - const char *pname; \ - const char *sig; \ - for (sig = signature; *sig; sig++) { \ - sig = _dbus_signature_end(sig); \ - if (!sig) { \ - len = 0; \ - break; \ - } \ - pname = va_arg(args, const char *); \ - len += strlen(pname) + 1; \ - } \ - len; \ - }) - -LIB_EXPORT bool l_dbus_interface_method(struct l_dbus_interface *interface, - const char *name, uint32_t flags, - l_dbus_interface_method_cb_t cb, - const char *return_sig, - const char *param_sig, ...) -{ - va_list args; - unsigned int return_info_len; - unsigned int param_info_len; - struct _dbus_method *info; - char *p; - - if (!_dbus_valid_method(name)) - return false; - - if (unlikely(!return_sig || !param_sig)) - return false; - - if (return_sig[0] && !_dbus_valid_signature(return_sig)) - return false; - - if (param_sig[0] && !_dbus_valid_signature(param_sig)) - return false; - - /* Pre-calculate the needed meta-info length */ - va_start(args, param_sig); - - return_info_len = SIZE_PARAMS(return_sig, args); - param_info_len = SIZE_PARAMS(param_sig, args); - - va_end(args); - - if (!return_info_len || !param_info_len) - return false; - - info = l_malloc(sizeof(*info) + return_info_len + - param_info_len + strlen(name) + 1); - info->cb = cb; - info->flags = flags; - info->name_len = strlen(name); - strcpy(info->metainfo, name); - - va_start(args, param_sig); - - /* - * We store param signature + parameter names first, to speed up - * lookups during the message dispatch procedures. - */ - p = info->metainfo + info->name_len + param_info_len + 1; - COPY_PARAMS(p, return_sig, args); - - p = info->metainfo + info->name_len + 1; - COPY_PARAMS(p, param_sig, args); - - va_end(args); - - l_queue_push_tail(interface->methods, info); - - return true; -} - -LIB_EXPORT bool l_dbus_interface_signal(struct l_dbus_interface *interface, - const char *name, uint32_t flags, - const char *signature, ...) -{ - va_list args; - unsigned int metainfo_len; - struct _dbus_signal *info; - char *p; - - if (!_dbus_valid_method(name)) - return false; - - if (unlikely(!signature)) - return false; - - if (signature[0] && !_dbus_valid_signature(signature)) - return false; - - /* Pre-calculate the needed meta-info length */ - va_start(args, signature); - metainfo_len = SIZE_PARAMS(signature, args); - va_end(args); - - if (!metainfo_len) - return false; - - metainfo_len += strlen(name) + 1; - - info = l_malloc(sizeof(*info) + metainfo_len); - info->flags = flags; - info->name_len = strlen(name); - - p = stpcpy(info->metainfo, name) + 1; - - va_start(args, signature); - COPY_PARAMS(p, signature, args); - va_end(args); - - l_queue_push_tail(interface->signals, info); - - return true; -} - -LIB_EXPORT bool l_dbus_interface_property(struct l_dbus_interface *interface, - const char *name, uint32_t flags, - const char *signature, - l_dbus_property_get_cb_t getter, - l_dbus_property_set_cb_t setter) -{ - unsigned int metainfo_len; - struct _dbus_property *info; - char *p; - - if (!_dbus_valid_method(name)) - return false; - - if (unlikely(!signature || !getter)) - return false; - - if (_dbus_num_children(signature) != 1) - return false; - - /* Pre-calculate the needed meta-info length */ - metainfo_len = strlen(name) + 1; - metainfo_len += strlen(signature) + 1; - - info = l_malloc(sizeof(*info) + metainfo_len); - info->flags = flags; - info->name_len = strlen(name); - info->getter = getter; - info->setter = setter; - - p = stpcpy(info->metainfo, name) + 1; - strcpy(p, signature); - - l_queue_push_tail(interface->properties, info); - - return true; -} - -struct l_dbus_interface *_dbus_interface_new(const char *name) -{ - struct l_dbus_interface *interface; - - interface = l_malloc(sizeof(*interface) + strlen(name) + 1); - - interface->methods = l_queue_new(); - interface->signals = l_queue_new(); - interface->properties = l_queue_new(); - - strcpy(interface->name, name); - - return interface; -} - -void _dbus_interface_free(struct l_dbus_interface *interface) -{ - l_queue_destroy(interface->methods, l_free); - l_queue_destroy(interface->signals, l_free); - l_queue_destroy(interface->properties, l_free); - - l_free(interface); -} - -static bool match_method(const void *a, const void *b) -{ - const struct _dbus_method *method = a; - const char *name = b; - - if (!strcmp(method->metainfo, name)) - return true; - - return false; -} - -struct _dbus_method *_dbus_interface_find_method(struct l_dbus_interface *i, - const char *method) -{ - return l_queue_find(i->methods, match_method, (char *) method); -} - -static bool match_signal(const void *a, const void *b) -{ - const struct _dbus_signal *signal = a; - const char *name = b; - - if (!strcmp(signal->metainfo, name)) - return true; - - return false; -} - -struct _dbus_signal *_dbus_interface_find_signal(struct l_dbus_interface *i, - const char *signal) -{ - return l_queue_find(i->signals, match_signal, (char *) signal); -} - -static bool match_property(const void *a, const void *b) -{ - const struct _dbus_property *property = a; - const char *name = b; - - if (!strcmp(property->metainfo, name)) - return true; - - return false; -} - -struct _dbus_property *_dbus_interface_find_property(struct l_dbus_interface *i, - const char *property) -{ - return l_queue_find(i->properties, match_property, (char *) property); -} - -static void interface_instance_free(struct interface_instance *instance) -{ - if (instance->interface->instance_destroy) - instance->interface->instance_destroy(instance->user_data); - - l_free(instance); -} - -static bool match_interface_instance(const void *a, const void *b) -{ - const struct interface_instance *instance = a; - const char *name = b; - - if (!strcmp(instance->interface->name, name)) - return true; - - return false; -} - -static bool match_interface_instance_ptr(const void *a, const void *b) -{ - const struct interface_instance *instance = a; - - return instance->interface == b; -} - -static void interface_add_record_free(void *data) -{ - struct interface_add_record *rec = data; - - l_free(rec->path); - l_queue_destroy(rec->instances, NULL); - l_free(rec); -} - -static void interface_removed_record_free(void *data) -{ - struct interface_remove_record *rec = data; - - l_free(rec->path); - l_queue_destroy(rec->interface_names, l_free); - l_free(rec); -} - -static void property_change_record_free(void *data) -{ - struct property_change_record *rec = data; - - l_free(rec->path); - l_queue_destroy(rec->properties, NULL); - l_free(rec); -} - -static void properties_setup_func(struct l_dbus_interface *); -static void object_manager_setup_func(struct l_dbus_interface *); - -struct _dbus_object_tree *_dbus_object_tree_new() -{ - struct _dbus_object_tree *tree; - - tree = l_new(struct _dbus_object_tree, 1); - - tree->interfaces = l_hashmap_new(); - l_hashmap_set_hash_function(tree->interfaces, l_str_hash); - l_hashmap_set_compare_function(tree->interfaces, - (l_hashmap_compare_func_t)strcmp); - - tree->objects = l_hashmap_string_new(); - - tree->root = l_new(struct object_node, 1); - - tree->property_changes = l_queue_new(); - - _dbus_object_tree_register_interface(tree, L_DBUS_INTERFACE_PROPERTIES, - properties_setup_func, NULL, - false); - - tree->object_managers = l_queue_new(); - - _dbus_object_tree_register_interface(tree, - L_DBUS_INTERFACE_OBJECT_MANAGER, - object_manager_setup_func, NULL, - false); - - return tree; -} - -static void subtree_free(struct object_node *node) -{ - struct child_node *child; - - while (node->children) { - child = node->children; - node->children = child->next; - - subtree_free(child->node); - l_free(child); - } - - l_queue_destroy(node->instances, - (l_queue_destroy_func_t) interface_instance_free); - - if (node->destroy) - node->destroy(node->user_data); - - l_free(node); -} - -static void object_manager_free(void *data) -{ - struct object_manager *manager = data; - - l_free(manager->path); - l_queue_destroy(manager->announce_added, interface_add_record_free); - l_queue_destroy(manager->announce_removed, - interface_removed_record_free); - l_free(manager); -} - -void _dbus_object_tree_free(struct _dbus_object_tree *tree) -{ - subtree_free(tree->root); - - l_hashmap_destroy(tree->interfaces, - (l_hashmap_destroy_func_t) _dbus_interface_free); - l_hashmap_destroy(tree->objects, NULL); - - l_queue_destroy(tree->object_managers, object_manager_free); - - l_queue_destroy(tree->property_changes, property_change_record_free); - - if (tree->emit_signals_work) - l_idle_remove(tree->emit_signals_work); - - l_free(tree); -} - -static struct object_node *makepath_recurse(struct object_node *node, - const char *path) -{ - const char *end; - struct child_node *child; - - if (*path == '\0') - return node; - - path += 1; - end = strchrnul(path, '/'); - child = node->children; - - while (child) { - if (!strncmp(child->subpath, path, end - path) && - child->subpath[end - path] == '\0') - goto done; - - child = child->next; - } - - child = l_malloc(sizeof(*child) + end - path + 1); - child->node = l_new(struct object_node, 1); - child->node->parent = node; - memcpy(child->subpath, path, end - path); - child->subpath[end-path] = '\0'; - child->next = node->children; - node->children = child; - -done: - return makepath_recurse(child->node, end); -} - -struct object_node *_dbus_object_tree_makepath(struct _dbus_object_tree *tree, - const char *path) -{ - if (path[0] == '/' && path[1] == '\0') - return tree->root; - - return makepath_recurse(tree->root, path); -} - -static struct object_node *lookup_recurse(struct object_node *node, - const char *path) -{ - const char *end; - struct child_node *child; - - if (*path == '\0') - return node; - - path += 1; - end = strchrnul(path, '/'); - child = node->children; - - while (child) { - if (!strncmp(child->subpath, path, end - path) && - child->subpath[end - path] == '\0') - return lookup_recurse(child->node, end); - - child = child->next; - } - - return NULL; -} - -struct object_node *_dbus_object_tree_lookup(struct _dbus_object_tree *tree, - const char *path) -{ - if (path[0] == '/' && path[1] == '\0') - return tree->root; - - return lookup_recurse(tree->root, path); -} - -void _dbus_object_tree_prune_node(struct object_node *node) -{ - struct object_node *parent = node->parent; - struct child_node *p = NULL, *c; - - while (parent) { - for (c = parent->children, p = NULL; c; p = c, c = c->next) { - if (c->node != node) - continue; - - if (p) - p->next = c->next; - else - parent->children = c->next; - - subtree_free(c->node); - l_free(c); - - break; - } - - if (parent->children != NULL) - return; - - if (parent->instances) - return; - - node = parent; - parent = node->parent; - } -} - -struct object_node *_dbus_object_tree_new_object(struct _dbus_object_tree *tree, - const char *path, - void *user_data, - void (*destroy) (void *)) -{ - struct object_node *node; - - if (!_dbus_valid_object_path(path)) - return NULL; - - if (l_hashmap_lookup(tree->objects, path)) - return NULL; - - node = _dbus_object_tree_makepath(tree, path); - node->user_data = user_data; - node->destroy = destroy; - - /* - * Registered objects in the tree are marked by being present in the - * tree->objects hash and having non-null node->instances. Remaining - * nodes are intermediate path elements added and removed - * automatically. - */ - node->instances = l_queue_new(); - - l_hashmap_insert(tree->objects, path, node); - - return node; -} - -bool _dbus_object_tree_object_destroy(struct _dbus_object_tree *tree, - const char *path) -{ - struct object_node *node; - const struct l_queue_entry *entry; - const struct interface_instance *instance; - - node = l_hashmap_lookup(tree->objects, path); - if (!node) - return false; - - while ((entry = l_queue_get_entries(node->instances))) { - instance = entry->data; - - if (!_dbus_object_tree_remove_interface(tree, path, - instance->interface->name)) - return false; - } - - l_hashmap_remove(tree->objects, path); - - l_queue_destroy(node->instances, NULL); - node->instances = NULL; - - if (node->destroy) { - node->destroy(node->user_data); - node->destroy = NULL; - } - - if (!node->children) - _dbus_object_tree_prune_node(node); - - return true; -} - -static bool get_properties_dict(struct l_dbus *dbus, - struct l_dbus_message *message, - struct l_dbus_message_builder *builder, - const struct l_dbus_interface *interface, - void *user_data) -{ - const struct l_queue_entry *entry; - const struct _dbus_property *property; - const char *signature; - - l_dbus_message_builder_enter_array(builder, "{sv}"); - _dbus_message_builder_mark(builder); - - for (entry = l_queue_get_entries(interface->properties); entry; - entry = entry->next) { - property = entry->data; - signature = property->metainfo + strlen(property->metainfo) + 1; - - l_dbus_message_builder_enter_dict(builder, "sv"); - l_dbus_message_builder_append_basic(builder, 's', - property->metainfo); - l_dbus_message_builder_enter_variant(builder, signature); - - if (!property->getter(dbus, message, builder, user_data)) { - if (!_dbus_message_builder_rewind(builder)) - return false; - - continue; - } - - l_dbus_message_builder_leave_variant(builder); - l_dbus_message_builder_leave_dict(builder); - _dbus_message_builder_mark(builder); - } - - l_dbus_message_builder_leave_array(builder); - - return true; -} - -static struct l_dbus_message *build_interfaces_removed_signal( - const struct object_manager *manager, - const struct interface_remove_record *rec) -{ - struct l_dbus_message *signal; - struct l_dbus_message_builder *builder; - const struct l_queue_entry *entry; - - signal = l_dbus_message_new_signal(manager->dbus, manager->path, - L_DBUS_INTERFACE_OBJECT_MANAGER, - "InterfacesRemoved"); - - builder = l_dbus_message_builder_new(signal); - - l_dbus_message_builder_append_basic(builder, 'o', rec->path); - l_dbus_message_builder_enter_array(builder, "s"); - - for (entry = l_queue_get_entries(rec->interface_names); entry; - entry = entry->next) - l_dbus_message_builder_append_basic(builder, 's', entry->data); - - l_dbus_message_builder_leave_array(builder); - l_dbus_message_builder_finalize(builder); - l_dbus_message_builder_destroy(builder); - - return signal; -} - -static struct l_dbus_message *build_interfaces_added_signal( - const struct object_manager *manager, - const struct interface_add_record *rec) -{ - struct l_dbus_message *signal; - struct l_dbus_message_builder *builder; - const struct l_queue_entry *entry; - const struct interface_instance *instance; - - signal = l_dbus_message_new_signal(manager->dbus, manager->path, - L_DBUS_INTERFACE_OBJECT_MANAGER, - "InterfacesAdded"); - - builder = l_dbus_message_builder_new(signal); - - l_dbus_message_builder_append_basic(builder, 'o', rec->path); - l_dbus_message_builder_enter_array(builder, "{sa{sv}}"); - - for (entry = l_queue_get_entries(rec->instances); entry; - entry = entry->next) { - instance = entry->data; - - l_dbus_message_builder_enter_dict(builder, "sa{sv}"); - l_dbus_message_builder_append_basic(builder, 's', - instance->interface->name); - - if (!get_properties_dict(manager->dbus, signal, builder, - instance->interface, - instance->user_data)) { - l_dbus_message_builder_destroy(builder); - l_dbus_message_unref(signal); - - return NULL; - } - - l_dbus_message_builder_leave_dict(builder); - } - - l_dbus_message_builder_leave_array(builder); - l_dbus_message_builder_finalize(builder); - l_dbus_message_builder_destroy(builder); - - return signal; -} - -static struct l_dbus_message *build_old_property_changed_signal( - struct l_dbus *dbus, - const struct property_change_record *rec, - const struct _dbus_property *property) -{ - struct l_dbus_message *signal; - struct l_dbus_message_builder *builder; - const char *signature; - - signature = property->metainfo + strlen(property->metainfo) + 1; - - signal = l_dbus_message_new_signal(dbus, rec->path, - rec->instance->interface->name, - "PropertyChanged"); - - builder = l_dbus_message_builder_new(signal); - - l_dbus_message_builder_append_basic(builder, 's', property->metainfo); - l_dbus_message_builder_enter_variant(builder, signature); - - if (!property->getter(dbus, signal, builder, - rec->instance->user_data)) { - l_dbus_message_builder_destroy(builder); - l_dbus_message_unref(signal); - - return NULL; - } - - l_dbus_message_builder_leave_variant(builder); - - l_dbus_message_builder_finalize(builder); - l_dbus_message_builder_destroy(builder); - - return signal; -} - -static struct l_dbus_message *build_properties_changed_signal( - struct l_dbus *dbus, - const struct property_change_record *rec) -{ - struct l_dbus_message *signal; - struct l_dbus_message_builder *builder; - const struct l_queue_entry *entry; - const struct _dbus_property *property; - const char *signature; - struct l_queue *invalidated; - - signal = l_dbus_message_new_signal(dbus, rec->path, - L_DBUS_INTERFACE_PROPERTIES, - "PropertiesChanged"); - - builder = l_dbus_message_builder_new(signal); - - invalidated = l_queue_new(); - - l_dbus_message_builder_append_basic(builder, 's', - rec->instance->interface->name); - l_dbus_message_builder_enter_array(builder, "{sv}"); - - for (entry = l_queue_get_entries(rec->properties); entry; - entry = entry->next) { - property = entry->data; - signature = property->metainfo + strlen(property->metainfo) + 1; - - _dbus_message_builder_mark(builder); - - l_dbus_message_builder_enter_dict(builder, "sv"); - l_dbus_message_builder_append_basic(builder, 's', - property->metainfo); - l_dbus_message_builder_enter_variant(builder, signature); - - if (!property->getter(dbus, signal, builder, - rec->instance->user_data)) { - if (!_dbus_message_builder_rewind(builder)) { - l_dbus_message_unref(signal); - signal = NULL; - - goto done; - } - - l_queue_push_tail(invalidated, (void *) property); - - continue; - } - - l_dbus_message_builder_leave_variant(builder); - l_dbus_message_builder_leave_dict(builder); - } - - l_dbus_message_builder_leave_array(builder); - l_dbus_message_builder_enter_array(builder, "s"); - - while ((property = l_queue_pop_head(invalidated))) - l_dbus_message_builder_append_basic(builder, 's', - property->metainfo); - - l_dbus_message_builder_leave_array(builder); - l_dbus_message_builder_finalize(builder); - -done: - l_dbus_message_builder_destroy(builder); - - l_queue_destroy(invalidated, NULL); - - return signal; -} - -struct emit_signals_data { - struct l_dbus *dbus; - struct object_manager *manager; - struct object_node *node; -}; - -static bool emit_interfaces_removed(void *data, void *user_data) -{ - struct interface_remove_record *rec = data; - struct emit_signals_data *es = user_data; - struct l_dbus_message *signal; - - if (es->node && rec->object != es->node) - return false; - - signal = build_interfaces_removed_signal(es->manager, rec); - interface_removed_record_free(rec); - - if (signal) - l_dbus_send(es->manager->dbus, signal); - - return true; -} - -static bool emit_interfaces_added(void *data, void *user_data) -{ - struct interface_add_record *rec = data; - struct emit_signals_data *es = user_data; - struct l_dbus_message *signal; - - if (es->node && rec->object != es->node) - return false; - - signal = build_interfaces_added_signal(es->manager, rec); - interface_add_record_free(rec); - - if (signal) - l_dbus_send(es->manager->dbus, signal); - - return true; -} - -static bool emit_properties_changed(void *data, void *user_data) -{ - struct property_change_record *rec = data; - struct emit_signals_data *es = user_data; - struct l_dbus_message *signal; - const struct l_queue_entry *entry; - - if (es->node && rec->object != es->node) - return false; - - if (rec->instance->interface->handle_old_style_properties) - for (entry = l_queue_get_entries(rec->properties); - entry; entry = entry->next) { - signal = build_old_property_changed_signal(es->dbus, - rec, entry->data); - if (signal) - l_dbus_send(es->dbus, signal); - } - - if (l_queue_find(rec->object->instances, match_interface_instance, - L_DBUS_INTERFACE_PROPERTIES)) { - signal = build_properties_changed_signal(es->dbus, rec); - if (signal) - l_dbus_send(es->dbus, signal); - } - - property_change_record_free(rec); - - return true; -} - -void _dbus_object_tree_signals_flush(struct l_dbus *dbus, const char *path) -{ - struct _dbus_object_tree *tree = _dbus_get_tree(dbus); - const struct l_queue_entry *entry; - struct emit_signals_data data; - bool all_done = true; - - if (!tree->emit_signals_work || tree->flushing) - return; - - tree->flushing = true; - - data.dbus = dbus; - data.node = path ? _dbus_object_tree_lookup(tree, path) : NULL; - - for (entry = l_queue_get_entries(tree->object_managers); entry; - entry = entry->next) { - data.manager = entry->data; - - l_queue_foreach_remove(data.manager->announce_removed, - emit_interfaces_removed, &data); - - if (!l_queue_isempty(data.manager->announce_removed)) - all_done = false; - - l_queue_foreach_remove(data.manager->announce_added, - emit_interfaces_added, &data); - - if (!l_queue_isempty(data.manager->announce_added)) - all_done = false; - } - - l_queue_foreach_remove(tree->property_changes, - emit_properties_changed, &data); - - if (!l_queue_isempty(tree->property_changes)) - all_done = false; - - if (all_done) { - l_idle_remove(tree->emit_signals_work); - tree->emit_signals_work = NULL; - } - - tree->flushing = false; -} - -static void emit_signals(struct l_idle *idle, void *user_data) -{ - struct l_dbus *dbus = user_data; - - _dbus_object_tree_signals_flush(dbus, NULL); -} - -static void schedule_emit_signals(struct l_dbus *dbus) -{ - struct _dbus_object_tree *tree = _dbus_get_tree(dbus); - - if (tree->emit_signals_work) - return; - - tree->emit_signals_work = l_idle_create(emit_signals, dbus, NULL); -} - -static bool match_property_changes_instance(const void *a, const void *b) -{ - const struct property_change_record *rec = a; - - return rec->instance == b; -} - -static bool match_pointer(const void *a, const void *b) -{ - return a == b; -} - -bool _dbus_object_tree_property_changed(struct l_dbus *dbus, - const char *path, - const char *interface_name, - const char *property_name) -{ - struct property_change_record *rec; - struct object_node *object; - struct interface_instance *instance; - struct _dbus_property *property; - struct _dbus_object_tree *tree = _dbus_get_tree(dbus); - - object = l_hashmap_lookup(tree->objects, path); - if (!object) - return false; - - instance = l_queue_find(object->instances, match_interface_instance, - interface_name); - if (!instance) - return false; - - property = _dbus_interface_find_property(instance->interface, - property_name); - if (!property) - return false; - - rec = l_queue_find(tree->property_changes, - match_property_changes_instance, instance); - - if (rec) { - if (l_queue_find(rec->properties, match_pointer, property)) - return true; - } else { - rec = l_new(struct property_change_record, 1); - rec->path = l_strdup(path); - rec->object = object; - rec->instance = instance; - rec->properties = l_queue_new(); - - l_queue_push_tail(tree->property_changes, rec); - } - - l_queue_push_tail(rec->properties, property); - - schedule_emit_signals(dbus); - - return true; -} - -static void pending_property_set_done(struct l_dbus *dbus, - struct l_dbus_message *message, - struct l_dbus_message *reply) -{ - const char *member; - const char *interface_name; - const char *property_name; - struct l_dbus_message_iter variant; - - if (!reply) { - reply = l_dbus_message_new_method_return(message); - l_dbus_message_set_arguments(reply, ""); - } - - l_dbus_send(dbus, l_dbus_message_ref(reply)); - - member = l_dbus_message_get_member(message); - if (!strcmp(member, "SetProperty")) { - if (!l_dbus_message_get_arguments(message, "sv", - &property_name, &variant)) - goto done; - - interface_name = l_dbus_message_get_interface(message); - } else if (strcmp(member, "Set") || - !l_dbus_message_get_arguments(message, "ssv", - &interface_name, - &property_name, - &variant)) - goto done; - - _dbus_object_tree_property_changed(dbus, - l_dbus_message_get_path(message), - interface_name, property_name); -done: - l_dbus_message_unref(message); - l_dbus_message_unref(reply); -} - -static struct l_dbus_message *old_set_property(struct l_dbus *dbus, - struct l_dbus_message *message, - void *user_data) -{ - struct l_dbus_interface *interface; - const char *property_name; - const struct _dbus_property *property; - struct l_dbus_message_iter variant; - struct _dbus_object_tree *tree = _dbus_get_tree(dbus); - struct l_dbus_message *reply; - - interface = l_hashmap_lookup(tree->interfaces, - l_dbus_message_get_interface(message)); - /* If we got here the interface must exist */ - - if (!l_dbus_message_get_arguments(message, "sv", &property_name, - &variant)) - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "InvalidArgs", - "Invalid arguments"); - - property = _dbus_interface_find_property(interface, property_name); - if (!property) - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "InvalidArgs", - "Unknown Property %s", - property_name); - - if (!property->setter) - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "InvalidArgs", - "Property %s is read-only", - property_name); - - reply = property->setter(dbus, l_dbus_message_ref(message), &variant, - pending_property_set_done, user_data); - - if (reply) - pending_property_set_done(dbus, message, reply); - - return NULL; -} - -static struct l_dbus_message *old_get_properties(struct l_dbus *dbus, - struct l_dbus_message *message, - void *user_data) -{ - const struct l_dbus_interface *interface; - struct l_dbus_message *reply; - struct l_dbus_message_builder *builder; - struct _dbus_object_tree *tree = _dbus_get_tree(dbus); - - interface = l_hashmap_lookup(tree->interfaces, - l_dbus_message_get_interface(message)); - /* If we got here the interface must exist */ - - reply = l_dbus_message_new_method_return(message); - builder = l_dbus_message_builder_new(reply); - - if (!get_properties_dict(dbus, message, builder, interface, - user_data)) { - l_dbus_message_unref(reply); - - reply = l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "Failed", - "Getting properties failed"); - } else - l_dbus_message_builder_finalize(builder); - - l_dbus_message_builder_destroy(builder); - - return reply; -} - -bool _dbus_object_tree_register_interface(struct _dbus_object_tree *tree, - const char *interface, - void (*setup_func)(struct l_dbus_interface *), - void (*destroy) (void *), - bool old_style_properties) -{ - struct l_dbus_interface *dbi; - - if (!_dbus_valid_interface(interface)) - return false; - - /* - * Check to make sure we do not have this interface already - * registered - */ - dbi = l_hashmap_lookup(tree->interfaces, interface); - if (dbi) - return false; - - dbi = _dbus_interface_new(interface); - dbi->instance_destroy = destroy; - dbi->handle_old_style_properties = old_style_properties; - - /* Add our methods first so we don't have to check for conflicts. */ - if (old_style_properties) { - l_dbus_interface_method(dbi, "SetProperty", 0, - old_set_property, "", "sv", - "name", "value"); - l_dbus_interface_method(dbi, "GetProperties", 0, - old_get_properties, "a{sv}", "", - "properties"); - - l_dbus_interface_signal(dbi, "PropertyChanged", 0, "sv", - "name", "value"); - } - - setup_func(dbi); - - l_hashmap_insert(tree->interfaces, dbi->name, dbi); - - return true; -} - -struct interface_check { - struct _dbus_object_tree *tree; - const char *interface; -}; - -static void check_interface_used(const void *key, void *value, void *user_data) -{ - const char *path = key; - struct object_node *node = value; - struct interface_check *state = user_data; - - if (!l_queue_find(node->instances, match_interface_instance, - (char *) state->interface)) - return; - - _dbus_object_tree_remove_interface(state->tree, path, state->interface); -} - -bool _dbus_object_tree_unregister_interface(struct _dbus_object_tree *tree, - const char *interface_name) -{ - struct l_dbus_interface *interface; - struct interface_check state = { tree, interface_name }; - - interface = l_hashmap_lookup(tree->interfaces, interface_name); - if (!interface) - return false; - - /* Check that the interface is not in use */ - l_hashmap_foreach(tree->objects, check_interface_used, &state); - - l_hashmap_remove(tree->interfaces, interface_name); - - _dbus_interface_free(interface); - - return true; -} - -static void collect_instances(struct object_node *node, - const char *path, - struct l_queue *announce) -{ - const struct l_queue_entry *entry; - struct interface_add_record *change_rec; - const struct child_node *child; - - if (!node->instances) - goto recurse; - - change_rec = l_new(struct interface_add_record, 1); - change_rec->path = l_strdup(path); - change_rec->object = node; - change_rec->instances = l_queue_new(); - - for (entry = l_queue_get_entries(node->instances); entry; - entry = entry->next) - l_queue_push_tail(change_rec->instances, entry->data); - - l_queue_push_tail(announce, change_rec); - -recurse: - if (!strcmp(path, "/")) - path = ""; - - for (child = node->children; child; child = child->next) { - char *child_path; - - child_path = l_strdup_printf("%s/%s", path, child->subpath); - - collect_instances(child->node, child_path, announce); - - l_free(child_path); - } -} - -static bool match_interfaces_added_object(const void *a, const void *b) -{ - const struct interface_add_record *rec = a; - - return rec->object == b; -} - -static bool match_interfaces_removed_object(const void *a, const void *b) -{ - const struct interface_remove_record *rec = a; - - return rec->object == b; -} - -bool _dbus_object_tree_add_interface(struct _dbus_object_tree *tree, - const char *path, const char *interface, - void *user_data) -{ - struct object_node *object; - struct l_dbus_interface *dbi; - struct interface_instance *instance; - const struct l_queue_entry *entry; - struct object_manager *manager; - size_t path_len; - struct interface_add_record *change_rec; - - dbi = l_hashmap_lookup(tree->interfaces, interface); - if (!dbi) - return false; - - object = l_hashmap_lookup(tree->objects, path); - if (!object) { - object = _dbus_object_tree_new_object(tree, path, NULL, NULL); - - if (!object) - return false; - } - - /* - * Check to make sure we do not have this interface already - * registered for this object - */ - if (l_queue_find(object->instances, match_interface_instance_ptr, dbi)) - return false; - - instance = l_new(struct interface_instance, 1); - instance->interface = dbi; - instance->user_data = user_data; - - l_queue_push_tail(object->instances, instance); - - for (entry = l_queue_get_entries(tree->object_managers); entry; - entry = entry->next) { - manager = entry->data; - path_len = strlen(manager->path); - - if (strncmp(path, manager->path, path_len) || - (path[path_len] != '\0' && - path[path_len] != '/' && path_len > 1)) - continue; - - change_rec = l_queue_find(manager->announce_added, - match_interfaces_added_object, - object); - if (!change_rec) { - change_rec = l_new(struct interface_add_record, 1); - change_rec->path = l_strdup(path); - change_rec->object = object; - change_rec->instances = l_queue_new(); - - l_queue_push_tail(manager->announce_added, change_rec); - } - - /* No need to check for duplicates here */ - l_queue_push_tail(change_rec->instances, instance); - - schedule_emit_signals(manager->dbus); - } - - if (!strcmp(interface, L_DBUS_INTERFACE_OBJECT_MANAGER)) { - manager = l_new(struct object_manager, 1); - manager->path = l_strdup(path); - manager->dbus = instance->user_data; - manager->announce_added = l_queue_new(); - manager->announce_removed = l_queue_new(); - - l_queue_push_tail(tree->object_managers, manager); - - /* Emit InterfacesAdded for interfaces added before OM */ - collect_instances(object, path, manager->announce_added); - - if (manager->dbus && !l_queue_isempty(manager->announce_added)) - schedule_emit_signals(manager->dbus); - } - - return true; -} - -void *_dbus_object_tree_get_interface_data(struct _dbus_object_tree *tree, - const char *path, - const char *interface) -{ - struct object_node *object; - struct interface_instance *instance; - - object = l_hashmap_lookup(tree->objects, path); - if (!object) - return NULL; - - instance = l_queue_find(object->instances, match_interface_instance, - (char *) interface); - if (!instance) - return NULL; - - return instance->user_data; -} - -static bool match_object_manager_path(const void *a, const void *b) -{ - const struct object_manager *manager = a; - - return !strcmp(manager->path, b); -} - -bool _dbus_object_tree_remove_interface(struct _dbus_object_tree *tree, - const char *path, const char *interface) -{ - struct object_node *node; - struct interface_instance *instance; - const struct l_queue_entry *entry; - struct object_manager *manager; - size_t path_len; - struct interface_add_record *interfaces_added_rec; - struct interface_remove_record *interfaces_removed_rec; - struct property_change_record *property_change_rec; - - node = l_hashmap_lookup(tree->objects, path); - if (!node) - return false; - - instance = l_queue_remove_if(node->instances, - match_interface_instance, (char *) interface); - if (!instance) - return false; - - if (!strcmp(interface, L_DBUS_INTERFACE_OBJECT_MANAGER)) { - manager = l_queue_remove_if(tree->object_managers, - match_object_manager_path, - (char *) path); - - if (manager) - object_manager_free(manager); - } - - for (entry = l_queue_get_entries(tree->object_managers); entry; - entry = entry->next) { - manager = entry->data; - path_len = strlen(manager->path); - - if (strncmp(path, manager->path, path_len) || - (path[path_len] != '\0' && - path[path_len] != '/' && path_len > 1)) - continue; - - interfaces_added_rec = l_queue_find(manager->announce_added, - match_interfaces_added_object, - node); - if (interfaces_added_rec && l_queue_remove( - interfaces_added_rec->instances, - instance)) { - if (l_queue_isempty(interfaces_added_rec->instances)) - l_queue_remove(manager->announce_added, - interfaces_added_rec); - - interface_add_record_free(interfaces_added_rec); - - continue; - } - - interfaces_removed_rec = l_queue_find(manager->announce_removed, - match_interfaces_removed_object, - node); - if (!interfaces_removed_rec) { - interfaces_removed_rec = - l_new(struct interface_remove_record, 1); - interfaces_removed_rec->path = l_strdup(path); - interfaces_removed_rec->object = node; - interfaces_removed_rec->interface_names = - l_queue_new(); - l_queue_push_tail(manager->announce_removed, - interfaces_removed_rec); - } - - /* No need to check for duplicates here */ - l_queue_push_tail(interfaces_removed_rec->interface_names, - l_strdup(interface)); - - schedule_emit_signals(manager->dbus); - } - - property_change_rec = l_queue_remove_if(tree->property_changes, - match_property_changes_instance, - instance); - if (property_change_rec) - property_change_record_free(property_change_rec); - - interface_instance_free(instance); - - return true; -} - -static void generate_interface_instance(void *data, void *user) -{ - struct interface_instance *instance = data; - struct l_string *buf = user; - - _dbus_interface_introspection(instance->interface, buf); -} - -void _dbus_object_tree_introspect(struct _dbus_object_tree *tree, - const char *path, struct l_string *buf) -{ - struct object_node *node; - struct child_node *child; - - node = l_hashmap_lookup(tree->objects, path); - if (!node) - node = _dbus_object_tree_lookup(tree, path); - - l_string_append(buf, XML_HEAD); - l_string_append(buf, "\n"); - - if (node) { - l_string_append(buf, static_introspectable); - l_queue_foreach(node->instances, - generate_interface_instance, buf); - - for (child = node->children; child; child = child->next) - l_string_append_printf(buf, "\t\n", - child->subpath); - } - - l_string_append(buf, "\n"); -} - -bool _dbus_object_tree_dispatch(struct _dbus_object_tree *tree, - struct l_dbus *dbus, - struct l_dbus_message *message) -{ - const char *path; - const char *interface; - const char *member; - const char *msg_sig; - const char *sig; - struct object_node *node; - struct interface_instance *instance; - struct _dbus_method *method; - struct l_dbus_message *reply; - - path = l_dbus_message_get_path(message); - interface = l_dbus_message_get_interface(message); - member = l_dbus_message_get_member(message); - msg_sig = l_dbus_message_get_signature(message); - - if (!msg_sig) - msg_sig = ""; - - if (!strcmp(interface, "org.freedesktop.DBus.Introspectable") && - !strcmp(member, "Introspect") && - !strcmp(msg_sig, "")) { - struct l_string *buf; - char *xml; - - buf = l_string_new(0); - _dbus_object_tree_introspect(tree, path, buf); - xml = l_string_unwrap(buf); - - reply = l_dbus_message_new_method_return(message); - l_dbus_message_set_arguments(reply, "s", xml); - l_dbus_send(dbus, reply); - - l_free(xml); - - return true; - } - - node = l_hashmap_lookup(tree->objects, path); - if (!node) - return false; - - instance = l_queue_find(node->instances, - match_interface_instance, (char *) interface); - if (!instance) - return false; - - method = _dbus_interface_find_method(instance->interface, member); - if (!method) - return false; - - sig = method->metainfo + method->name_len + 1; - - if (strcmp(msg_sig, sig)) - return false; - - reply = method->cb(dbus, message, instance->user_data); - if (reply) - l_dbus_send(dbus, reply); - - return true; -} - -LIB_EXPORT bool l_dbus_property_changed(struct l_dbus *dbus, const char *path, - const char *interface, - const char *property) -{ - return _dbus_object_tree_property_changed(dbus, path, interface, - property); -} - -static struct l_dbus_message *properties_get(struct l_dbus *dbus, - struct l_dbus_message *message, - void *user_data) -{ - const struct interface_instance *instance; - const char *interface_name, *property_name, *signature; - const struct _dbus_property *property; - struct _dbus_object_tree *tree = _dbus_get_tree(dbus); - const struct object_node *object; - struct l_dbus_message *reply; - struct l_dbus_message_builder *builder; - - if (!l_dbus_message_get_arguments(message, "ss", &interface_name, - &property_name)) - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "InvalidArgs", - "Invalid arguments"); - - object = l_hashmap_lookup(tree->objects, - l_dbus_message_get_path(message)); - /* If we got here the object must exist */ - - instance = l_queue_find(object->instances, - match_interface_instance, - (char *) interface_name); - if (!instance) - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "InvalidArgs", - "Object has no interface %s", - interface_name); - - property = _dbus_interface_find_property(instance->interface, - property_name); - if (!property) - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "InvalidArgs", - "Unknown Property %s", - property_name); - - - reply = l_dbus_message_new_method_return(message); - builder = l_dbus_message_builder_new(reply); - - signature = property->metainfo + strlen(property->metainfo) + 1; - - l_dbus_message_builder_enter_variant(builder, signature); - - if (property->getter(dbus, message, builder, instance->user_data)) { - l_dbus_message_builder_leave_variant(builder); - l_dbus_message_builder_finalize(builder); - } else { - l_dbus_message_unref(reply); - - reply = l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "Failed", - "Getting property value " - "failed"); - } - - l_dbus_message_builder_destroy(builder); - - return reply; -} - -static struct l_dbus_message *properties_set(struct l_dbus *dbus, - struct l_dbus_message *message, - void *user_data) -{ - struct l_dbus_interface *interface; - const struct interface_instance *instance; - const char *interface_name, *property_name; - const struct _dbus_property *property; - struct l_dbus_message_iter variant; - struct _dbus_object_tree *tree = _dbus_get_tree(dbus); - const struct object_node *object; - struct l_dbus_message *reply; - - if (!l_dbus_message_get_arguments(message, "ssv", &interface_name, - &property_name, &variant)) - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "InvalidArgs", - "Invalid arguments"); - - interface = l_hashmap_lookup(tree->interfaces, interface_name); - if (!interface) - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "InvalidArgs", - "Unknown Interface %s", - interface_name); - - property = _dbus_interface_find_property(interface, property_name); - if (!property) - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "InvalidArgs", - "Unknown Property %s", - property_name); - - if (!property->setter) - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "InvalidArgs", - "Property %s is read-only", - property_name); - - object = l_hashmap_lookup(tree->objects, - l_dbus_message_get_path(message)); - /* If we got here the object must exist */ - - instance = l_queue_find(object->instances, - match_interface_instance_ptr, interface); - if (!instance) - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "InvalidArgs", - "Object has no interface %s", - interface_name); - - reply = property->setter(dbus, l_dbus_message_ref(message), &variant, - pending_property_set_done, - instance->user_data); - - if (reply) - pending_property_set_done(dbus, message, reply); - - return NULL; -} - -static struct l_dbus_message *properties_get_all(struct l_dbus *dbus, - struct l_dbus_message *message, - void *user_data) -{ - const struct interface_instance *instance; - const char *interface_name; - struct _dbus_object_tree *tree = _dbus_get_tree(dbus); - const struct object_node *object; - struct l_dbus_message *reply; - struct l_dbus_message_builder *builder; - - if (!l_dbus_message_get_arguments(message, "s", &interface_name)) - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "InvalidArgs", - "Invalid arguments"); - - object = l_hashmap_lookup(tree->objects, - l_dbus_message_get_path(message)); - /* If we got here the object must exist */ - - instance = l_queue_find(object->instances, - match_interface_instance, - (char *) interface_name); - if (!instance) - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "InvalidArgs", - "Object has no interface %s", - interface_name); - - reply = l_dbus_message_new_method_return(message); - builder = l_dbus_message_builder_new(reply); - - if (!get_properties_dict(dbus, message, builder, instance->interface, - instance->user_data)) { - l_dbus_message_unref(reply); - - reply = l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "Failed", - "Getting property values " - "failed"); - } else - l_dbus_message_builder_finalize(builder); - - l_dbus_message_builder_destroy(builder); - - return reply; -} - -static void properties_setup_func(struct l_dbus_interface *interface) -{ - l_dbus_interface_method(interface, "Get", 0, - properties_get, "v", "ss", - "value", "interface_name", "property_name"); - l_dbus_interface_method(interface, "Set", 0, - properties_set, "", "ssv", - "interface_name", "property_name", "value"); - l_dbus_interface_method(interface, "GetAll", 0, - properties_get_all, "a{sv}", "s", - "props", "interface_name"); - - l_dbus_interface_signal(interface, "PropertiesChanged", 0, "sa{sv}as", - "interface_name", "changed_properties", - "invalidated_properties"); -} - -static bool collect_objects(struct l_dbus *dbus, struct l_dbus_message *message, - struct l_dbus_message_builder *builder, - const struct object_node *node, - const char *path) -{ - const struct l_queue_entry *entry; - const struct child_node *child; - char *child_path; - const struct interface_instance *instance; - bool r; - - if (!node->instances) - goto recurse; - - l_dbus_message_builder_enter_dict(builder, "oa{sa{sv}}"); - l_dbus_message_builder_append_basic(builder, 'o', path); - l_dbus_message_builder_enter_array(builder, "{sa{sv}}"); - - for (entry = l_queue_get_entries(node->instances); entry; - entry = entry->next) { - instance = entry->data; - - l_dbus_message_builder_enter_dict(builder, "sa{sv}"); - l_dbus_message_builder_append_basic(builder, 's', - instance->interface->name); - - if (!get_properties_dict(dbus, message, builder, - instance->interface, - instance->user_data)) - return false; - - l_dbus_message_builder_leave_dict(builder); - } - - l_dbus_message_builder_leave_array(builder); - l_dbus_message_builder_leave_dict(builder); - -recurse: - if (!strcmp(path, "/")) - path = ""; - - for (child = node->children; child; child = child->next) { - child_path = l_strdup_printf("%s/%s", path, child->subpath); - - r = collect_objects(dbus, message, builder, - child->node, child_path); - - l_free(child_path); - - if (!r) - return false; - } - - return true; -} - -struct l_dbus_message *_dbus_object_tree_get_objects( - struct _dbus_object_tree *tree, - struct l_dbus *dbus, - const char *path, - struct l_dbus_message *message) -{ - const struct object_node *node; - struct l_dbus_message *reply; - struct l_dbus_message_builder *builder; - - node = l_hashmap_lookup(tree->objects, path); - - reply = l_dbus_message_new_method_return(message); - builder = l_dbus_message_builder_new(reply); - - l_dbus_message_builder_enter_array(builder, "{oa{sa{sv}}}"); - - if (!collect_objects(dbus, message, builder, node, path)) { - l_dbus_message_builder_destroy(builder); - l_dbus_message_unref(reply); - - return l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error." - "Failed", - "Getting property values " - "failed"); - } - - l_dbus_message_builder_leave_array(builder); - - l_dbus_message_builder_finalize(builder); - l_dbus_message_builder_destroy(builder); - - return reply; -} - -static struct l_dbus_message *get_managed_objects(struct l_dbus *dbus, - struct l_dbus_message *message, - void *user_data) -{ - struct _dbus_object_tree *tree = _dbus_get_tree(dbus); - const char *path = l_dbus_message_get_path(message); - - return _dbus_object_tree_get_objects(tree, dbus, path, message); -} - -static void object_manager_setup_func(struct l_dbus_interface *interface) -{ - l_dbus_interface_method(interface, "GetManagedObjects", 0, - get_managed_objects, "a{oa{sa{sv}}}", "", - "objpath_interfaces_and_properties"); - - l_dbus_interface_signal(interface, "InterfacesAdded", 0, "oa{sa{sv}}", - "object_path", "interfaces_and_properties"); - l_dbus_interface_signal(interface, "InterfacesRemoved", 0, "oas", - "object_path", "interfaces"); -} diff --git a/ell/dbus-service.h b/ell/dbus-service.h deleted file mode 100644 index 153bb3a..0000000 --- a/ell/dbus-service.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_SERVICE_H -#define __ELL_SERVICE_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_dbus; -struct l_dbus_interface; -struct l_dbus_message; - -enum l_dbus_method_flag { - L_DBUS_METHOD_FLAG_DEPRECATED = 1, - L_DBUS_METHOD_FLAG_NOREPLY = 2, - L_DBUS_METHOD_FLAG_ASYNC = 4, -}; - -enum l_dbus_signal_flag { - L_DBUS_SIGNAL_FLAG_DEPRECATED = 1, -}; - -enum l_dbus_property_flag { - L_DBUS_PROPERTY_FLAG_DEPRECATED = 1, -}; - -typedef struct l_dbus_message *(*l_dbus_interface_method_cb_t) (struct l_dbus *, - struct l_dbus_message *message, - void *user_data); - -typedef void (*l_dbus_property_complete_cb_t) (struct l_dbus *, - struct l_dbus_message *, - struct l_dbus_message *error); - -typedef struct l_dbus_message *(*l_dbus_property_set_cb_t) (struct l_dbus *, - struct l_dbus_message *message, - struct l_dbus_message_iter *new_value, - l_dbus_property_complete_cb_t complete, - void *user_data); - -typedef bool (*l_dbus_property_get_cb_t) (struct l_dbus *, - struct l_dbus_message *message, - struct l_dbus_message_builder *builder, - void *user_data); - -bool l_dbus_interface_method(struct l_dbus_interface *interface, - const char *name, uint32_t flags, - l_dbus_interface_method_cb_t cb, - const char *return_sig, const char *param_sig, - ...); - -bool l_dbus_interface_signal(struct l_dbus_interface *interface, - const char *name, uint32_t flags, - const char *signature, ...); - -bool l_dbus_interface_property(struct l_dbus_interface *interface, - const char *name, uint32_t flags, - const char *signature, - l_dbus_property_get_cb_t getter, - l_dbus_property_set_cb_t setter); - -bool l_dbus_property_changed(struct l_dbus *dbus, const char *path, - const char *interface, const char *property); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_DBUS_SERVICE_H */ diff --git a/ell/dbus-util.c b/ell/dbus-util.c deleted file mode 100644 index e4f8f78..0000000 --- a/ell/dbus-util.c +++ /dev/null @@ -1,1305 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include - -#include "dbus.h" -#include "private.h" -#include "dbus-private.h" -#include "string.h" -#include "queue.h" - -#define DBUS_MAX_INTERFACE_LEN 255 -#define DBUS_MAX_METHOD_LEN 255 - -static const char *simple_types = "sogybnqiuxtdh"; - -static int get_alignment(const char type) -{ - switch (type) { - case 'b': - return 4; - case 'y': - return 1; - case 'n': - case 'q': - return 2; - case 'u': - case 'i': - return 4; - case 'x': - case 't': - case 'd': - return 8; - case 's': - case 'o': - return 4; - case 'g': - return 1; - case 'a': - return 4; - case '(': - case '{': - return 8; - case 'v': - return 1; - case 'h': - return 4; - default: - return 0; - } -} - -static int get_basic_size(const char type) -{ - switch (type) { - case 'b': - return 4; - case 'y': - return 1; - case 'n': - case 'q': - return 2; - case 'i': - case 'u': - return 4; - case 'x': - case 't': - return 8; - case 'd': - return 8; - case 'h': - return 4; - default: - return 0; - } -} - -static inline bool is_valid_character(const char c, bool bus_name) -{ - if (c >= 'a' && c <= 'z') - return true; - - if (c >= 'A' && c <= 'Z') - return true; - - if (c >= '0' && c <= '9') - return true; - - if (c == '_') - return true; - - if (c == '-' && bus_name) - return true; - - return false; -} - -bool _dbus_valid_object_path(const char *path) -{ - unsigned int i; - char c = '\0'; - - if (path == NULL) - return false; - - if (path[0] == '\0') - return false; - - if (path[0] && !path[1] && path[0] == '/') - return true; - - if (path[0] != '/') - return false; - - for (i = 0; path[i]; i++) { - if (path[i] == '/' && c == '/') - return false; - - c = path[i]; - - if (is_valid_character(path[i], false) || path[i] == '/') - continue; - - return false; - } - - if (path[i-1] == '/') - return false; - - return true; -} - -static const char *validate_next_type(const char *sig) -{ - char s = *sig; - - if (s == '\0') - return NULL; - - if (strchr(simple_types, s) || s == 'v') - return sig + 1; - - switch (s) { - case 'a': - s = *++sig; - - if (s == '{') { - s = *++sig; - - /* Dictionary keys can only be simple types */ - if (!strchr(simple_types, s)) - return NULL; - - sig = validate_next_type(sig + 1); - - if (!sig) - return NULL; - - if (*sig != '}') - return NULL; - - return sig + 1; - } - - return validate_next_type(sig); - - case '(': - sig++; - - do - sig = validate_next_type(sig); - while (sig && *sig != ')'); - - if (!sig) - return NULL; - - return sig + 1; - } - - return NULL; -} - -static bool valid_dict_signature(const char *sig) -{ - char s = *sig; - - if (s != '{') - return false; - - s = *++sig; - - if (!strchr(simple_types, s)) - return false; - - sig = validate_next_type(sig + 1); - if (!sig) - return false; - - if (sig[0] != '}') - return false; - - if (sig[1] != '\0') - return false; - - return true; -} - -bool _dbus_valid_signature(const char *sig) -{ - const char *s = sig; - - do { - s = validate_next_type(s); - - if (!s) - return false; - } while (*s); - - return true; -} - -int _dbus_num_children(const char *sig) -{ - const char *s = sig; - int num_children = 0; - - do { - s = validate_next_type(s); - - if (!s) - return -1; - - num_children += 1; - } while (*s); - - return num_children; -} - -static bool valid_member_name(const char *start, const char *end, - bool bus_name) -{ - const char *p; - - if ((end - start) < 1) - return false; - - if (*start >= '0' && *start <= '9') - return false; - - for (p = start; p < end; p++) - if (!is_valid_character(*p, bus_name)) - return false; - - return true; -} - -bool _dbus_valid_method(const char *method) -{ - unsigned int i; - - if (!method) - return false; - - if (method[0] == '\0' || strlen(method) > DBUS_MAX_METHOD_LEN) - return false; - - if (method[0] >= '0' && method[0] <= '9') - return false; - - for (i = 0; method[i]; i++) - if (!is_valid_character(method[i], false)) - return false; - - return true; -} - -bool _dbus_valid_interface(const char *interface) -{ - const char *sep; - - if (!interface) - return false; - - if (interface[0] == '\0' || strlen(interface) > DBUS_MAX_INTERFACE_LEN) - return false; - - sep = strchrnul(interface, '.'); - if (*sep == '\0') - return false; - - while (true) { - if (!valid_member_name(interface, sep, false)) - return false; - - if (*sep == '\0') - break; - - interface = sep + 1; - sep = strchrnul(interface, '.'); - } - - return true; -} - -bool _dbus_parse_unique_name(const char *name, uint64_t *out_id) -{ - char *endp = NULL; - uint64_t r; - - if (!l_str_has_prefix(name, ":1.")) - return false; - - errno = 0; - r = strtoull(name + 3, &endp, 10); - if (!endp || endp == name || *endp || errno) - return false; - - if (out_id) - *out_id = r; - - return true; -} - -bool _dbus_valid_bus_name(const char *bus_name) -{ - const char *sep; - - if (!bus_name) - return false; - - if (bus_name[0] == '\0' || strlen(bus_name) > DBUS_MAX_INTERFACE_LEN) - return false; - - if (_dbus_parse_unique_name(bus_name, NULL)) - return true; - - sep = strchrnul(bus_name, '.'); - if (*sep == '\0') - return false; - - while (true) { - if (!valid_member_name(bus_name, sep, true)) - return false; - - if (*sep == '\0') - break; - - bus_name = sep + 1; - sep = strchrnul(bus_name, '.'); - } - - return true; -} - -const char *_dbus_signature_end(const char *signature) -{ - const char *ptr = signature; - unsigned int indent = 0; - char expect; - - switch (*signature) { - case '(': - expect = ')'; - break; - case '{': - expect = '}'; - break; - case 'a': - return _dbus_signature_end(signature + 1); - default: - return signature; - } - - for (ptr = signature; *ptr != '\0'; ptr++) { - if (*ptr == *signature) - indent++; - else if (*ptr == expect) - if (!--indent) - return ptr; - } - - return NULL; -} - -bool _dbus1_header_is_valid(void *data, size_t size) -{ - struct dbus_header *hdr; - size_t header_len; - - if (size < sizeof(struct dbus_header)) - return false; - - hdr = data; - - if (hdr->endian != DBUS_NATIVE_ENDIAN) - header_len = bswap_32(hdr->dbus1.field_length); - else - header_len = hdr->dbus1.field_length; - - header_len += sizeof(struct dbus_header); - return size >= header_len; -} - -static inline void dbus1_iter_init_internal(struct l_dbus_message_iter *iter, - struct l_dbus_message *message, - enum dbus_container_type type, - const char *sig_start, - const char *sig_end, - const void *data, size_t len, - size_t pos) -{ - size_t sig_len; - - iter->message = message; - - if (sig_end) - sig_len = sig_end - sig_start; - else - sig_len = strlen(sig_start); - - iter->sig_start = sig_start; - iter->sig_len = sig_len; - iter->sig_pos = 0; - iter->data = data; - iter->len = pos + len; - iter->pos = pos; - iter->container_type = type; -} - -void _dbus1_iter_init(struct l_dbus_message_iter *iter, - struct l_dbus_message *message, - const char *sig_start, const char *sig_end, - const void *data, size_t len) -{ - dbus1_iter_init_internal(iter, message, DBUS_CONTAINER_TYPE_STRUCT, - sig_start, sig_end, data, len, 0); -} - -static const char *calc_len_next_item(const char *signature, const void *data, - size_t data_pos, size_t data_len, - size_t *out_len) -{ - unsigned int alignment; - size_t pos; - size_t len; - const char *sig_end; - const char *var_sig; - - alignment = get_alignment(*signature); - if (alignment == 0) - return NULL; - - pos = align_len(data_pos, alignment); - if (pos > data_len) - return NULL; - - switch (*signature) { - case 'o': - case 's': - if (pos + 5 > data_len) - return NULL; - - pos += l_get_u32(data + pos) + 5; - break; - case 'g': - if (pos + 2 > data_len) - return NULL; - - pos += l_get_u8(data + pos) + 2; - break; - case 'y': - pos += 1; - break; - case 'n': - case 'q': - pos += 2; - break; - case 'b': - case 'i': - case 'u': - case 'h': - pos += 4; - break; - case 'x': - case 't': - case 'd': - pos += 8; - break; - case 'a': - if (pos + 4 > data_len) - return NULL; - - len = l_get_u32(data + pos); - pos += 4; - - alignment = get_alignment(signature[1]); - pos = align_len(pos, alignment); - pos += len; - - sig_end = _dbus_signature_end(signature) + 1; - goto done; - case '(': - sig_end = signature + 1; - - while (*sig_end != ')') { - sig_end = calc_len_next_item(sig_end, data, pos, - data_len, &len); - - if (!sig_end) - return NULL; - - pos += len; - } - - sig_end += 1; - goto done; - case '{': - sig_end = calc_len_next_item(signature + 1, data, pos, - data_len, &len); - - if (!sig_end) - return NULL; - - pos += len; - - sig_end = calc_len_next_item(sig_end, data, pos, - data_len, &len); - - if (!sig_end) - return NULL; - - pos += len; - sig_end += 1; - goto done; - case 'v': - if (!calc_len_next_item("g", data, pos, data_len, &len)) - return NULL; - - var_sig = data + pos + 1; - pos += len; - - if (!calc_len_next_item(var_sig, data, pos, data_len, &len)) - return NULL; - - pos += len; - break; - default: - return NULL; - } - - sig_end = signature + 1; - -done: - if (pos > data_len) - return NULL; - - *out_len = pos - data_pos; - return sig_end; -} - -bool _dbus1_iter_next_entry_basic(struct l_dbus_message_iter *iter, - char type, void *out) -{ - const char *str_val; - uint8_t uint8_val; - uint16_t uint16_val; - uint32_t uint32_val; - uint64_t uint64_val; - int16_t int16_val; - int32_t int32_val; - int64_t int64_val; - size_t pos; - - if (iter->pos >= iter->len) - return false; - - pos = align_len(iter->pos, get_alignment(type)); - - switch (type) { - case 'o': - case 's': - if (pos + 5 > iter->len) - return false; - uint32_val = l_get_u32(iter->data + pos); - str_val = iter->data + pos + 4; - *(const void **) out = str_val; - iter->pos = pos + uint32_val + 5; - break; - case 'g': - if (pos + 2 > iter->len) - return false; - uint8_val = l_get_u8(iter->data + pos); - str_val = iter->data + pos + 1; - *(const void **) out = str_val; - iter->pos = pos + uint8_val + 2; - break; - case 'b': - if (pos + 4 > iter->len) - return false; - uint32_val = l_get_u32(iter->data + pos); - *(bool *) out = !!uint32_val; - iter->pos = pos + 4; - break; - case 'y': - if (pos + 1 > iter->len) - return false; - uint8_val = l_get_u8(iter->data + pos); - *(uint8_t *) out = uint8_val; - iter->pos = pos + 1; - break; - case 'n': - if (pos + 2 > iter->len) - return false; - int16_val = l_get_s16(iter->data + pos); - *(int16_t *) out = int16_val; - iter->pos = pos + 2; - break; - case 'q': - if (pos + 2 > iter->len) - return false; - uint16_val = l_get_u16(iter->data + pos); - *(uint16_t *) out = uint16_val; - iter->pos = pos + 2; - break; - case 'i': - if (pos + 4 > iter->len) - return false; - int32_val = l_get_s32(iter->data + pos); - *(int32_t *) out = int32_val; - iter->pos = pos + 4; - break; - case 'u': - case 'h': - if (pos + 4 > iter->len) - return false; - uint32_val = l_get_u32(iter->data + pos); - *(uint32_t *) out = uint32_val; - iter->pos = pos + 4; - break; - case 'x': - if (pos + 8 > iter->len) - return false; - int64_val = l_get_s64(iter->data + pos); - *(int64_t *) out= int64_val; - iter->pos = pos + 8; - break; - case 't': - case 'd': - if (pos + 8 > iter->len) - return false; - uint64_val = l_get_u64(iter->data + pos); - *(uint64_t *) out = uint64_val; - iter->pos = pos + 8; - break; - default: - return false; - } - - if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY) - iter->sig_pos += 1; - - return true; -} - -bool _dbus1_iter_get_fixed_array(struct l_dbus_message_iter *iter, - void *out, uint32_t *n_elem) -{ - char type; - uint32_t size; - - if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY) - return false; - - type = iter->sig_start[iter->sig_pos]; - size = get_basic_size(type); - - /* Fail if the array is not a fixed size or contains file descriptors */ - if (!size || type == 'n') - return false; - - /* - * enter_array should already align us to our container type, so - * there is no need to align pos here - */ - *(const void **) out = iter->data + iter->pos; - *n_elem = (iter->len - iter->pos) / size; - - return true; -} - -bool _dbus1_iter_enter_struct(struct l_dbus_message_iter *iter, - struct l_dbus_message_iter *structure) -{ - size_t len; - size_t pos; - const char *sig_start; - const char *sig_end; - bool is_dict = iter->sig_start[iter->sig_pos] == '{'; - bool is_struct = iter->sig_start[iter->sig_pos] == '('; - - if (!is_dict && !is_struct) - return false; - - pos = align_len(iter->pos, 8); - if (pos >= iter->len) - return false; - - sig_start = iter->sig_start + iter->sig_pos + 1; - sig_end = _dbus_signature_end(iter->sig_start + iter->sig_pos); - - if (!calc_len_next_item(iter->sig_start + iter->sig_pos, - iter->data, pos, iter->len, &len)) - return false; - - dbus1_iter_init_internal(structure, iter->message, - DBUS_CONTAINER_TYPE_STRUCT, - sig_start, sig_end, iter->data, - len, pos); - - if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY) - iter->sig_pos += sig_end - sig_start + 2; - - iter->pos = pos + len; - - return true; -} - -bool _dbus1_iter_enter_variant(struct l_dbus_message_iter *iter, - struct l_dbus_message_iter *variant) -{ - size_t pos; - uint8_t sig_len; - size_t len; - const char *sig_start; - - if (iter->sig_start[iter->sig_pos] != 'v') - return false; - - pos = align_len(iter->pos, 1); - if (pos + 2 > iter->len) - return false; - - sig_len = l_get_u8(iter->data + pos); - sig_start = iter->data + pos + 1; - - if (!calc_len_next_item(sig_start, iter->data, pos + sig_len + 2, - iter->len, &len)) - return false; - - dbus1_iter_init_internal(variant, iter->message, - DBUS_CONTAINER_TYPE_VARIANT, - sig_start, NULL, iter->data, - len, pos + sig_len + 2); - - if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY) - iter->sig_pos += 1; - - iter->pos = pos + sig_len + 2 + len; - - return true; -} - -bool _dbus1_iter_enter_array(struct l_dbus_message_iter *iter, - struct l_dbus_message_iter *array) -{ - size_t pos; - size_t len; - const char *sig_start; - const char *sig_end; - - if (iter->sig_start[iter->sig_pos] != 'a') - return false; - - sig_start = iter->sig_start + iter->sig_pos + 1; - sig_end = _dbus_signature_end(sig_start) + 1; - - pos = align_len(iter->pos, 4); - if (pos + 4 > iter->len) - return false; - - len = l_get_u32(iter->data + pos); - pos += 4; - - pos = align_len(pos, get_alignment(*sig_start)); - dbus1_iter_init_internal(array, iter->message, - DBUS_CONTAINER_TYPE_ARRAY, - sig_start, sig_end, - iter->data, len, pos); - - if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY) - iter->sig_pos += sig_end - sig_start + 1; - - iter->pos = pos + len; - - return true; -} - -bool _dbus1_iter_skip_entry(struct l_dbus_message_iter *iter) -{ - size_t len; - const char *sig_end; - - sig_end = calc_len_next_item(iter->sig_start + iter->sig_pos, - iter->data, iter->pos, iter->len, &len); - if (!sig_end) - return false; - - iter->pos += len; - iter->sig_pos = sig_end - iter->sig_start; - - return true; -} - -struct dbus_builder { - struct l_string *signature; - void *body; - size_t body_size; - size_t body_pos; - struct l_queue *containers; - struct { - struct container *container; - int sig_end; - size_t body_pos; - } mark; -}; - -struct container { - size_t start; - enum dbus_container_type type; - char signature[256]; - uint8_t sigindex; -}; - -static struct container *container_new(enum dbus_container_type type, - const char *signature, size_t start) -{ - struct container *ret; - - ret = l_new(struct container, 1); - - ret->type = type; - strcpy(ret->signature, signature); - ret->start = start; - - return ret; -} - -static void container_free(struct container *container) -{ - l_free(container); -} - -static inline size_t grow_body(struct dbus_builder *builder, - size_t len, unsigned int alignment) -{ - size_t size = align_len(builder->body_pos, alignment); - - if (size + len > builder->body_size) { - builder->body = l_realloc(builder->body, size + len); - builder->body_size = size + len; - } - - if (size - builder->body_pos > 0) - memset(builder->body + builder->body_pos, 0, - size - builder->body_pos); - - builder->body_pos = size + len; - - return size; -} - -struct dbus_builder *_dbus1_builder_new(void *body, size_t body_size) -{ - struct dbus_builder *builder; - struct container *root; - - builder = l_new(struct dbus_builder, 1); - builder->signature = l_string_new(63); - - builder->containers = l_queue_new(); - root = container_new(DBUS_CONTAINER_TYPE_STRUCT, "", 0); - l_queue_push_head(builder->containers, root); - - builder->body = body; - builder->body_size = body_size; - builder->body_pos = body_size; - - builder->mark.container = root; - builder->mark.sig_end = 0; - builder->mark.body_pos = 0; - - return builder; -} - -void _dbus1_builder_free(struct dbus_builder *builder) -{ - if (unlikely(!builder)) - return; - - l_string_free(builder->signature); - l_queue_destroy(builder->containers, - (l_queue_destroy_func_t) container_free); - l_free(builder->body); - - l_free(builder); -} - -bool _dbus1_builder_append_basic(struct dbus_builder *builder, - char type, const void *value) -{ - struct container *container = l_queue_peek_head(builder->containers); - size_t start; - unsigned int alignment; - size_t len; - - if (unlikely(!builder)) - return false; - - if (unlikely(!strchr(simple_types, type))) - return false; - - alignment = get_alignment(type); - if (!alignment) - return false; - - if (l_queue_length(builder->containers) == 1) - l_string_append_c(builder->signature, type); - else if (container->signature[container->sigindex] != type) - return false; - - len = get_basic_size(type); - - if (len) { - uint32_t b; - - start = grow_body(builder, len, alignment); - - if (type == 'b') { - b = *(bool *)value; - memcpy(builder->body + start, &b, len); - } else - memcpy(builder->body + start, value, len); - - if (container->type != DBUS_CONTAINER_TYPE_ARRAY) - container->sigindex += 1; - - return true; - } - - len = strlen(value); - - if (type == 'g') { - start = grow_body(builder, len + 2, 1); - l_put_u8(len, builder->body + start); - strcpy(builder->body + start + 1, value); - } else { - start = grow_body(builder, len + 5, 4); - l_put_u32(len, builder->body + start); - strcpy(builder->body + start + 4, value); - } - - if (container->type != DBUS_CONTAINER_TYPE_ARRAY) - container->sigindex += 1; - - return true; -} - -static bool enter_struct_dict_common(struct dbus_builder *builder, - const char *signature, - enum dbus_container_type type, - const char open, - const char close) -{ - size_t qlen = l_queue_length(builder->containers); - struct container *container = l_queue_peek_head(builder->containers); - size_t start; - - if (qlen == 1) { - if (l_string_length(builder->signature) + - strlen(signature) + 2 > 255) - return false; - } else { - /* Verify Signatures Match */ - char expect[256]; - const char *start; - const char *end; - - start = container->signature + container->sigindex; - end = _dbus_signature_end(start); - - if (*start != open || *end != close) - return false; - - memcpy(expect, start + 1, end - start - 1); - expect[end - start - 1] = '\0'; - - if (strcmp(expect, signature)) - return false; - } - - start = grow_body(builder, 0, 8); - - container = container_new(type, signature, start); - l_queue_push_head(builder->containers, container); - - return true; -} - -bool _dbus1_builder_enter_struct(struct dbus_builder *builder, - const char *signature) -{ - if (!_dbus_valid_signature(signature)) - return false; - - return enter_struct_dict_common(builder, signature, - DBUS_CONTAINER_TYPE_STRUCT, '(', ')'); -} - -bool _dbus1_builder_enter_dict(struct dbus_builder *builder, - const char *signature) -{ - if (_dbus_num_children(signature) != 2) - return false; - - if (!strchr(simple_types, signature[0])) - return false; - - return enter_struct_dict_common(builder, signature, - DBUS_CONTAINER_TYPE_DICT_ENTRY, - '{', '}'); -} - -static bool leave_struct_dict_common(struct dbus_builder *builder, - enum dbus_container_type type, - const char open, - const char close) -{ - struct container *container = l_queue_peek_head(builder->containers); - size_t qlen = l_queue_length(builder->containers); - struct container *parent; - - if (unlikely(qlen <= 1)) - return false; - - if (unlikely(container->type != type)) - return false; - - l_queue_pop_head(builder->containers); - qlen -= 1; - parent = l_queue_peek_head(builder->containers); - - if (qlen == 1) - l_string_append_printf(builder->signature, "%c%s%c", - open, - container->signature, - close); - else if (parent->type != DBUS_CONTAINER_TYPE_ARRAY) - parent->sigindex += strlen(container->signature) + 2; - - container_free(container); - - return true; -} - -bool _dbus1_builder_leave_struct(struct dbus_builder *builder) -{ - return leave_struct_dict_common(builder, DBUS_CONTAINER_TYPE_STRUCT, - '(', ')'); -} - -bool _dbus1_builder_leave_dict(struct dbus_builder *builder) -{ - return leave_struct_dict_common(builder, - DBUS_CONTAINER_TYPE_DICT_ENTRY, - '{', '}'); -} - -bool _dbus1_builder_enter_variant(struct dbus_builder *builder, - const char *signature) -{ - size_t qlen = l_queue_length(builder->containers); - struct container *container = l_queue_peek_head(builder->containers); - size_t start; - size_t siglen; - - if (_dbus_num_children(signature) != 1) - return false; - - if (qlen == 1) { - if (l_string_length(builder->signature) + 1 > 255) - return false; - } else if (container->signature[container->sigindex] != 'v') - return false; - - siglen = strlen(signature); - start = grow_body(builder, siglen + 2, 1); - l_put_u8(siglen, builder->body + start); - strcpy(builder->body + start + 1, signature); - - container = container_new(DBUS_CONTAINER_TYPE_VARIANT, - signature, start); - l_queue_push_head(builder->containers, container); - - return true; -} - -bool _dbus1_builder_leave_variant(struct dbus_builder *builder) -{ - struct container *container = l_queue_peek_head(builder->containers); - size_t qlen = l_queue_length(builder->containers); - struct container *parent; - - if (unlikely(qlen <= 1)) - return false; - - if (unlikely(container->type != DBUS_CONTAINER_TYPE_VARIANT)) - return false; - - l_queue_pop_head(builder->containers); - qlen -= 1; - parent = l_queue_peek_head(builder->containers); - - if (qlen == 1) - l_string_append_c(builder->signature, 'v'); - else if (parent->type != DBUS_CONTAINER_TYPE_ARRAY) - parent->sigindex += 1; - - container_free(container); - - return true; -} - -bool _dbus1_builder_enter_array(struct dbus_builder *builder, - const char *signature) -{ - size_t qlen = l_queue_length(builder->containers); - struct container *container = l_queue_peek_head(builder->containers); - size_t start; - int alignment; - - if (_dbus_num_children(signature) != 1 && - !valid_dict_signature(signature)) - return false; - - if (qlen == 1) { - if (l_string_length(builder->signature) + - strlen(signature) + 1 > 255) - return false; - } else { - /* Verify Signatures Match */ - char expect[256]; - const char *start; - const char *end; - - start = container->signature + container->sigindex; - end = validate_next_type(start); - - if (*start != 'a') - return false; - - memcpy(expect, start + 1, end - start - 1); - expect[end - start - 1] = '\0'; - - if (strcmp(expect, signature)) - return false; - } - - /* First grow the body enough to cover preceding length */ - start = grow_body(builder, 4, 4); - - /* Now align to element alignment */ - alignment = get_alignment(*signature); - grow_body(builder, 0, alignment); - - container = container_new(DBUS_CONTAINER_TYPE_ARRAY, signature, start); - l_queue_push_head(builder->containers, container); - - return true; -} - -bool _dbus1_builder_leave_array(struct dbus_builder *builder) -{ - struct container *container = l_queue_peek_head(builder->containers); - size_t qlen = l_queue_length(builder->containers); - struct container *parent; - size_t alignment; - size_t array_start; - - if (unlikely(qlen <= 1)) - return false; - - if (unlikely(container->type != DBUS_CONTAINER_TYPE_ARRAY)) - return false; - - l_queue_pop_head(builder->containers); - qlen -= 1; - parent = l_queue_peek_head(builder->containers); - - if (qlen == 1) - l_string_append_printf(builder->signature, "a%s", - container->signature); - else if (parent->type != DBUS_CONTAINER_TYPE_ARRAY) - parent->sigindex += strlen(container->signature) + 1; - - /* Update array length */ - alignment = get_alignment(container->signature[0]); - array_start = align_len(container->start + 4, alignment); - - l_put_u32(builder->body_pos - array_start, - builder->body + container->start); - - container_free(container); - - return true; -} - -bool _dbus1_builder_mark(struct dbus_builder *builder) -{ - struct container *container = l_queue_peek_head(builder->containers); - - builder->mark.container = container; - - if (l_queue_length(builder->containers) == 1) - builder->mark.sig_end = l_string_length(builder->signature); - else - builder->mark.sig_end = container->sigindex; - - builder->mark.body_pos = builder->body_pos; - - return true; -} - -bool _dbus1_builder_rewind(struct dbus_builder *builder) -{ - struct container *container; - - while ((container = l_queue_peek_head(builder->containers)) != - builder->mark.container) { - container_free(container); - l_queue_pop_head(builder->containers); - } - - builder->body_pos = builder->mark.body_pos; - - if (l_queue_length(builder->containers) == 1) - l_string_truncate(builder->signature, builder->mark.sig_end); - else - container->sigindex = builder->mark.sig_end; - - return true; -} - -char *_dbus1_builder_finish(struct dbus_builder *builder, - void **body, size_t *body_size) -{ - char *signature; - - if (unlikely(!builder)) - return NULL; - - if (unlikely(l_queue_length(builder->containers) != 1)) - return NULL; - - signature = l_string_unwrap(builder->signature); - builder->signature = NULL; - - *body = builder->body; - *body_size = builder->body_pos; - builder->body = NULL; - builder->body_size = 0; - - return signature; -} diff --git a/ell/dbus.c b/ell/dbus.c deleted file mode 100644 index f8e0ec8..0000000 --- a/ell/dbus.c +++ /dev/null @@ -1,1814 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "io.h" -#include "idle.h" -#include "queue.h" -#include "hashmap.h" -#include "dbus.h" -#include "private.h" -#include "dbus-private.h" - -#define DEFAULT_SYSTEM_BUS_ADDRESS "unix:path=/var/run/dbus/system_bus_socket" - -#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" - -#define DBUS_PATH_DBUS "/org/freedesktop/DBus" - -#define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024 - -enum auth_state { - WAITING_FOR_OK, - WAITING_FOR_AGREE_UNIX_FD, - SETUP_DONE -}; - -struct l_dbus_ops { - char version; - bool (*send_message)(struct l_dbus *bus, - struct l_dbus_message *message); - struct l_dbus_message *(*recv_message)(struct l_dbus *bus); - void (*free)(struct l_dbus *bus); - struct _dbus_name_ops name_ops; - struct _dbus_filter_ops filter_ops; - uint32_t (*name_acquire)(struct l_dbus *dbus, const char *name, - bool allow_replacement, bool replace_existing, - bool queue, l_dbus_name_acquire_func_t callback, - void *user_data); -}; - -struct l_dbus { - struct l_io *io; - char *guid; - bool negotiate_unix_fd; - bool support_unix_fd; - bool is_ready; - char *unique_name; - unsigned int next_id; - uint32_t next_serial; - struct l_queue *message_queue; - struct l_hashmap *message_list; - struct l_hashmap *signal_list; - l_dbus_ready_func_t ready_handler; - l_dbus_destroy_func_t ready_destroy; - void *ready_data; - l_dbus_disconnect_func_t disconnect_handler; - l_dbus_destroy_func_t disconnect_destroy; - void *disconnect_data; - l_dbus_debug_func_t debug_handler; - l_dbus_destroy_func_t debug_destroy; - void *debug_data; - struct _dbus_object_tree *tree; - struct _dbus_name_cache *name_cache; - struct _dbus_filter *filter; - bool name_notify_enabled; - - const struct l_dbus_ops *driver; -}; - -struct l_dbus_classic { - struct l_dbus super; - void *auth_command; - enum auth_state auth_state; - struct l_hashmap *match_strings; - int *fd_buf; - unsigned int num_fds; -}; - -struct message_callback { - uint32_t serial; - struct l_dbus_message *message; - l_dbus_message_func_t callback; - l_dbus_destroy_func_t destroy; - void *user_data; -}; - -struct signal_callback { - unsigned int id; - l_dbus_message_func_t callback; - l_dbus_destroy_func_t destroy; - void *user_data; -}; - -static void message_queue_destroy(void *data) -{ - struct message_callback *callback = data; - - l_dbus_message_unref(callback->message); - - if (callback->destroy) - callback->destroy(callback->user_data); - - l_free(callback); -} - -static void message_list_destroy(void *value) -{ - message_queue_destroy(value); -} - -static void signal_list_destroy(void *value) -{ - struct signal_callback *callback = value; - - if (callback->destroy) - callback->destroy(callback->user_data); - - l_free(callback); -} - -static bool message_write_handler(struct l_io *io, void *user_data) -{ - struct l_dbus *dbus = user_data; - struct l_dbus_message *message; - struct message_callback *callback; - const void *header, *body; - size_t header_size, body_size; - - callback = l_queue_pop_head(dbus->message_queue); - if (!callback) - return false; - - message = callback->message; - if (_dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL && - callback->callback == NULL) - l_dbus_message_set_no_reply(message, true); - - _dbus_message_set_serial(message, callback->serial); - - if (!dbus->driver->send_message(dbus, message)) { - message_queue_destroy(callback); - return false; - } - - header = _dbus_message_get_header(message, &header_size); - body = _dbus_message_get_body(message, &body_size); - l_util_hexdump_two(false, header, header_size, body, body_size, - dbus->debug_handler, dbus->debug_data); - - if (callback->callback == NULL) { - message_queue_destroy(callback); - goto done; - } - - l_hashmap_insert(dbus->message_list, - L_UINT_TO_PTR(callback->serial), callback); - -done: - if (l_queue_isempty(dbus->message_queue)) - return false; - - /* Only continue sending messges if the connection is ready */ - return dbus->is_ready; -} - -static void handle_method_return(struct l_dbus *dbus, - struct l_dbus_message *message) -{ - struct message_callback *callback; - uint32_t reply_serial; - - reply_serial = _dbus_message_get_reply_serial(message); - if (reply_serial == 0) - return; - - callback = l_hashmap_remove(dbus->message_list, - L_UINT_TO_PTR(reply_serial)); - if (!callback) - return; - - if (callback->callback) - callback->callback(message, callback->user_data); - - message_queue_destroy(callback); -} - -static void handle_error(struct l_dbus *dbus, struct l_dbus_message *message) -{ - struct message_callback *callback; - uint32_t reply_serial; - - reply_serial = _dbus_message_get_reply_serial(message); - if (reply_serial == 0) - return; - - callback = l_hashmap_remove(dbus->message_list, - L_UINT_TO_PTR(reply_serial)); - if (!callback) - return; - - if (callback->callback) - callback->callback(message, callback->user_data); - - message_queue_destroy(callback); -} - -static void process_signal(const void *key, void *value, void *user_data) -{ - struct signal_callback *callback = value; - struct l_dbus_message *message = user_data; - - if (callback->callback) - callback->callback(message, callback->user_data); -} - -static void handle_signal(struct l_dbus *dbus, struct l_dbus_message *message) -{ - l_hashmap_foreach(dbus->signal_list, process_signal, message); -} - -static bool message_read_handler(struct l_io *io, void *user_data) -{ - struct l_dbus *dbus = user_data; - struct l_dbus_message *message; - const void *header, *body; - size_t header_size, body_size; - enum dbus_message_type msgtype; - - message = dbus->driver->recv_message(dbus); - if (!message) - return true; - - header = _dbus_message_get_header(message, &header_size); - body = _dbus_message_get_body(message, &body_size); - l_util_hexdump_two(true, header, header_size, body, body_size, - dbus->debug_handler, dbus->debug_data); - - msgtype = _dbus_message_get_type(message); - - switch (msgtype) { - case DBUS_MESSAGE_TYPE_METHOD_RETURN: - handle_method_return(dbus, message); - break; - case DBUS_MESSAGE_TYPE_ERROR: - handle_error(dbus, message); - break; - case DBUS_MESSAGE_TYPE_SIGNAL: - handle_signal(dbus, message); - break; - case DBUS_MESSAGE_TYPE_METHOD_CALL: - if (!_dbus_object_tree_dispatch(dbus->tree, dbus, message)) { - struct l_dbus_message *error; - - error = l_dbus_message_new_error(message, - "org.freedesktop.DBus.Error.NotFound", - "No matching method found"); - l_dbus_send(dbus, error); - } - - break; - } - - l_dbus_message_unref(message); - - return true; -} - -static uint32_t send_message(struct l_dbus *dbus, bool priority, - struct l_dbus_message *message, - l_dbus_message_func_t function, - void *user_data, l_dbus_destroy_func_t destroy) -{ - struct message_callback *callback; - enum dbus_message_type type; - const char *path; - - type = _dbus_message_get_type(message); - - if ((type == DBUS_MESSAGE_TYPE_METHOD_RETURN || - type == DBUS_MESSAGE_TYPE_ERROR) && - _dbus_message_get_reply_serial(message) == 0) { - l_dbus_message_unref(message); - return 0; - } - - /* Default empty signature for method return messages */ - if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN && - !l_dbus_message_get_signature(message)) - l_dbus_message_set_arguments(message, ""); - - callback = l_new(struct message_callback, 1); - - callback->serial = dbus->next_serial++; - callback->message = message; - callback->callback = function; - callback->destroy = destroy; - callback->user_data = user_data; - - if (priority) { - l_queue_push_head(dbus->message_queue, callback); - - l_io_set_write_handler(dbus->io, message_write_handler, - dbus, NULL); - - return callback->serial; - } - - path = l_dbus_message_get_path(message); - if (path) - _dbus_object_tree_signals_flush(dbus, path); - - l_queue_push_tail(dbus->message_queue, callback); - - if (dbus->is_ready) - l_io_set_write_handler(dbus->io, message_write_handler, - dbus, NULL); - - return callback->serial; -} - -static void bus_ready(struct l_dbus *dbus) -{ - dbus->is_ready = true; - - if (dbus->ready_handler) - dbus->ready_handler(dbus->ready_data); - - l_io_set_read_handler(dbus->io, message_read_handler, dbus, NULL); - - /* Check for messages added before the connection was ready */ - if (l_queue_isempty(dbus->message_queue)) - return; - - l_io_set_write_handler(dbus->io, message_write_handler, dbus, NULL); -} - -static void hello_callback(struct l_dbus_message *message, void *user_data) -{ - struct l_dbus *dbus = user_data; - const char *signature; - const char *unique_name; - - signature = l_dbus_message_get_signature(message); - if (!signature || strcmp(signature, "s")) { - close(l_io_get_fd(dbus->io)); - return; - } - - if (!l_dbus_message_get_arguments(message, "s", &unique_name)) { - close(l_io_get_fd(dbus->io)); - return; - } - - dbus->unique_name = l_strdup(unique_name); - - bus_ready(dbus); -} - -static bool auth_write_handler(struct l_io *io, void *user_data) -{ - struct l_dbus_classic *classic = user_data; - struct l_dbus *dbus = &classic->super; - ssize_t written, len; - int fd; - - fd = l_io_get_fd(io); - - if (!classic->auth_command) - return false; - - len = strlen(classic->auth_command); - if (!len) - return false; - - written = L_TFR(send(fd, classic->auth_command, len, 0)); - if (written < 0) - return false; - - l_util_hexdump(false, classic->auth_command, written, - dbus->debug_handler, dbus->debug_data); - - if (written < len) { - memmove(classic->auth_command, classic->auth_command + written, - len + 1 - written); - return true; - } - - l_free(classic->auth_command); - classic->auth_command = NULL; - - if (classic->auth_state == SETUP_DONE) { - struct l_dbus_message *message; - - l_io_set_read_handler(dbus->io, message_read_handler, - dbus, NULL); - - message = l_dbus_message_new_method_call(dbus, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - L_DBUS_INTERFACE_DBUS, - "Hello"); - l_dbus_message_set_arguments(message, ""); - - send_message(dbus, true, message, hello_callback, dbus, NULL); - - return true; - } - - return false; -} - -static bool auth_read_handler(struct l_io *io, void *user_data) -{ - struct l_dbus_classic *classic = user_data; - struct l_dbus *dbus = &classic->super; - char buffer[64]; - char *ptr, *end; - ssize_t offset, len; - int fd; - - fd = l_io_get_fd(io); - - ptr = buffer; - offset = 0; - - while (1) { - len = L_TFR(recv(fd, ptr + offset, - sizeof(buffer) - offset, - MSG_DONTWAIT)); - if (len < 0) { - if (errno != EAGAIN) - return false; - - break; - } - - offset += len; - } - - ptr = buffer; - len = offset; - - if (!ptr || len < 3) - return true; - - end = strstr(ptr, "\r\n"); - if (!end) - return true; - - if (end - ptr + 2 != len) - return true; - - l_util_hexdump(true, ptr, len, dbus->debug_handler, dbus->debug_data); - - *end = '\0'; - - switch (classic->auth_state) { - case WAITING_FOR_OK: - if (!strncmp(ptr, "OK ", 3)) { - enum auth_state state; - const char *command; - - if (dbus->negotiate_unix_fd) { - command = "NEGOTIATE_UNIX_FD\r\n"; - state = WAITING_FOR_AGREE_UNIX_FD; - } else { - command = "BEGIN\r\n"; - state = SETUP_DONE; - } - - l_free(dbus->guid); - dbus->guid = l_strdup(ptr + 3); - - classic->auth_command = l_strdup(command); - classic->auth_state = state; - break; - } else if (!strncmp(ptr, "REJECTED ", 9)) { - static const char *command = "AUTH ANONYMOUS\r\n"; - - dbus->negotiate_unix_fd = true; - - classic->auth_command = l_strdup(command); - classic->auth_state = WAITING_FOR_OK; - } - break; - - case WAITING_FOR_AGREE_UNIX_FD: - if (!strncmp(ptr, "AGREE_UNIX_FD", 13)) { - static const char *command = "BEGIN\r\n"; - - dbus->support_unix_fd = true; - - classic->auth_command = l_strdup(command); - classic->auth_state = SETUP_DONE; - break; - } else if (!strncmp(ptr, "ERROR", 5)) { - static const char *command = "BEGIN\r\n"; - - dbus->support_unix_fd = false; - - classic->auth_command = l_strdup(command); - classic->auth_state = SETUP_DONE; - break; - } - break; - - case SETUP_DONE: - break; - } - - l_io_set_write_handler(io, auth_write_handler, dbus, NULL); - - return true; -} - -static void disconnect_handler(struct l_io *io, void *user_data) -{ - struct l_dbus *dbus = user_data; - - dbus->is_ready = false; - - l_util_debug(dbus->debug_handler, dbus->debug_data, "disconnect"); - - if (dbus->disconnect_handler) - dbus->disconnect_handler(dbus->disconnect_data); -} - -static void dbus_init(struct l_dbus *dbus, int fd) -{ - dbus->io = l_io_new(fd); - l_io_set_close_on_destroy(dbus->io, true); - l_io_set_disconnect_handler(dbus->io, disconnect_handler, dbus, NULL); - - dbus->is_ready = false; - dbus->next_id = 1; - dbus->next_serial = 1; - - dbus->message_queue = l_queue_new(); - dbus->message_list = l_hashmap_new(); - dbus->signal_list = l_hashmap_new(); - - dbus->tree = _dbus_object_tree_new(); -} - -static void classic_free(struct l_dbus *dbus) -{ - struct l_dbus_classic *classic = - l_container_of(dbus, struct l_dbus_classic, super); - unsigned int i; - - for (i = 0; i < classic->num_fds; i++) - close(classic->fd_buf[i]); - l_free(classic->fd_buf); - - l_free(classic->auth_command); - l_hashmap_destroy(classic->match_strings, l_free); - l_free(classic); -} - -static bool classic_send_message(struct l_dbus *dbus, - struct l_dbus_message *message) -{ - int fd = l_io_get_fd(dbus->io); - struct msghdr msg; - struct iovec iov[2], *iovpos; - ssize_t r; - int *fds = NULL; - uint32_t num_fds = 0; - struct cmsghdr *cmsg; - int iovlen; - - iov[0].iov_base = _dbus_message_get_header(message, &iov[0].iov_len); - iov[1].iov_base = _dbus_message_get_body(message, &iov[1].iov_len); - - if (dbus->support_unix_fd) - fds = _dbus_message_get_fds(message, &num_fds); - - iovpos = iov; - iovlen = 2; - - while (1) { - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = iovpos; - msg.msg_iovlen = iovlen; - - if (num_fds) { - msg.msg_control = - alloca(CMSG_SPACE(num_fds * sizeof(int))); - msg.msg_controllen = CMSG_LEN(num_fds * sizeof(int)); - - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = msg.msg_controllen; - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - memcpy(CMSG_DATA(cmsg), fds, num_fds * sizeof(int)); - } - - r = L_TFR(sendmsg(fd, &msg, 0)); - if (r < 0) - return false; - - while ((size_t) r >= iovpos->iov_len) { - r -= iovpos->iov_len; - iovpos++; - iovlen--; - - if (!iovlen) - break; - } - - if (!iovlen) - break; - - iovpos->iov_base += r; - iovpos->iov_len -= r; - - /* The FDs have been transmitted, don't retransmit */ - num_fds = 0; - } - - return true; -} - -static struct l_dbus_message *classic_recv_message(struct l_dbus *dbus) -{ - struct l_dbus_classic *classic = - l_container_of(dbus, struct l_dbus_classic, super); - int fd = l_io_get_fd(dbus->io); - struct dbus_header hdr; - struct msghdr msg; - struct iovec iov[2], *iovpos; - struct cmsghdr *cmsg; - ssize_t len, r; - void *header, *body; - size_t header_size, body_size; - union { - uint8_t bytes[CMSG_SPACE(16 * sizeof(int))]; - struct cmsghdr align; - } fd_buf; - int *fds = NULL; - uint32_t num_fds = 0; - int iovlen; - struct l_dbus_message *message; - unsigned int i; - - len = recv(fd, &hdr, DBUS_HEADER_SIZE, MSG_PEEK | MSG_DONTWAIT); - if (len != DBUS_HEADER_SIZE) - return NULL; - - header_size = align_len(DBUS_HEADER_SIZE + hdr.dbus1.field_length, 8); - header = l_malloc(header_size); - - body_size = hdr.dbus1.body_length; - body = l_malloc(body_size); - - iov[0].iov_base = header; - iov[0].iov_len = header_size; - iov[1].iov_base = body; - iov[1].iov_len = body_size; - - iovpos = iov; - iovlen = 2; - - while (1) { - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = iovpos; - msg.msg_iovlen = iovlen; - msg.msg_control = &fd_buf; - msg.msg_controllen = sizeof(fd_buf); - - r = L_TFR(recvmsg(fd, &msg, - MSG_CMSG_CLOEXEC | MSG_WAITALL)); - if (r < 0) - goto cmsg_fail; - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level != SOL_SOCKET || - cmsg->cmsg_type != SCM_RIGHTS) - continue; - - num_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); - fds = (void *) CMSG_DATA(cmsg); - - /* Set FD_CLOEXEC on all file descriptors */ - for (i = 0; i < num_fds; i++) { - long flags; - - flags = fcntl(fds[i], F_GETFD, NULL); - if (flags < 0) - continue; - - if (!(flags & FD_CLOEXEC)) - fcntl(fds[i], F_SETFD, - flags | FD_CLOEXEC); - } - - classic->fd_buf = l_realloc(classic->fd_buf, - (classic->num_fds + num_fds) * - sizeof(int)); - memcpy(classic->fd_buf + classic->num_fds, fds, - num_fds * sizeof(int)); - classic->num_fds += num_fds; - } - - while ((size_t) r >= iovpos->iov_len) { - r -= iovpos->iov_len; - iovpos++; - iovlen--; - - if (!iovlen) - break; - } - - if (!iovlen) - break; - - iovpos->iov_base += r; - iovpos->iov_len -= r; - } - - if (hdr.endian != DBUS_NATIVE_ENDIAN) { - l_util_debug(dbus->debug_handler, - dbus->debug_data, "Endianness incorrect"); - goto bad_msg; - } - - if (hdr.version != 1) { - l_util_debug(dbus->debug_handler, - dbus->debug_data, "Protocol version incorrect"); - goto bad_msg; - } - - num_fds = _dbus_message_unix_fds_from_header(header, header_size); - if (num_fds > classic->num_fds) - goto bad_msg; - - message = dbus_message_build(header, header_size, body, body_size, - classic->fd_buf, num_fds); - - if (message && num_fds) { - if (classic->num_fds > num_fds) { - memmove(classic->fd_buf, classic->fd_buf + num_fds, - (classic->num_fds - num_fds) * sizeof(int)); - classic->num_fds -= num_fds; - } else { - l_free(classic->fd_buf); - - classic->fd_buf = NULL; - classic->num_fds = 0; - } - } - - if (message) - return message; - -bad_msg: -cmsg_fail: - for (i = 0; i < classic->num_fds; i++) - close(classic->fd_buf[i]); - - l_free(classic->fd_buf); - - classic->fd_buf = NULL; - classic->num_fds = 0; - - l_free(header); - l_free(body); - - return NULL; -} - -static bool classic_add_match(struct l_dbus *dbus, unsigned int id, - const struct _dbus_filter_condition *rule, - int rule_len) -{ - struct l_dbus_classic *classic = - l_container_of(dbus, struct l_dbus_classic, super); - char *match_str; - struct l_dbus_message *message; - - match_str = _dbus_filter_rule_to_str(rule, rule_len); - - l_hashmap_insert(classic->match_strings, L_UINT_TO_PTR(id), match_str); - - message = l_dbus_message_new_method_call(dbus, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - L_DBUS_INTERFACE_DBUS, - "AddMatch"); - - l_dbus_message_set_arguments(message, "s", match_str); - - send_message(dbus, false, message, NULL, NULL, NULL); - - return true; -} - -static bool classic_remove_match(struct l_dbus *dbus, unsigned int id) -{ - struct l_dbus_classic *classic = - l_container_of(dbus, struct l_dbus_classic, super); - char *match_str = l_hashmap_remove(classic->match_strings, - L_UINT_TO_PTR(id)); - struct l_dbus_message *message; - - if (!match_str) - return false; - - message = l_dbus_message_new_method_call(dbus, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - L_DBUS_INTERFACE_DBUS, - "RemoveMatch"); - - l_dbus_message_set_arguments(message, "s", match_str); - - send_message(dbus, false, message, NULL, NULL, NULL); - - l_free(match_str); - - return true; -} - -static void name_owner_changed_cb(struct l_dbus_message *message, - void *user_data) -{ - struct l_dbus *dbus = user_data; - char *name, *old, *new; - - if (!l_dbus_message_get_arguments(message, "sss", &name, &old, &new)) - return; - - _dbus_name_cache_notify(dbus->name_cache, name, new); -} - -struct get_name_owner_request { - struct l_dbus_message *message; - struct l_dbus *dbus; -}; - -static void get_name_owner_reply_cb(struct l_dbus_message *reply, - void *user_data) -{ - struct get_name_owner_request *req = user_data; - const char *name, *owner; - - /* No name owner yet */ - if (l_dbus_message_is_error(reply)) - return; - - /* Shouldn't happen */ - if (!l_dbus_message_get_arguments(reply, "s", &owner)) - return; - - /* Shouldn't happen */ - if (!l_dbus_message_get_arguments(req->message, "s", &name)) - return; - - _dbus_name_cache_notify(req->dbus->name_cache, name, owner); -} - -static bool classic_get_name_owner(struct l_dbus *bus, const char *name) -{ - struct get_name_owner_request *req; - - /* Name resolution is not performed for DBUS_SERVICE_DBUS */ - if (!strcmp(name, DBUS_SERVICE_DBUS)) - return false; - - req = l_new(struct get_name_owner_request, 1); - req->dbus = bus; - req->message = l_dbus_message_new_method_call(bus, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - L_DBUS_INTERFACE_DBUS, - "GetNameOwner"); - - l_dbus_message_set_arguments(req->message, "s", name); - - send_message(bus, false, req->message, get_name_owner_reply_cb, - req, l_free); - - if (!bus->name_notify_enabled) { - static struct _dbus_filter_condition rule[] = { - { L_DBUS_MATCH_TYPE, "signal" }, - { L_DBUS_MATCH_SENDER, DBUS_SERVICE_DBUS }, - { L_DBUS_MATCH_PATH, DBUS_PATH_DBUS }, - { L_DBUS_MATCH_INTERFACE, L_DBUS_INTERFACE_DBUS }, - { L_DBUS_MATCH_MEMBER, "NameOwnerChanged" }, - }; - - if (!bus->filter) - bus->filter = _dbus_filter_new(bus, - &bus->driver->filter_ops, - bus->name_cache); - - _dbus_filter_add_rule(bus->filter, rule, L_ARRAY_SIZE(rule), - name_owner_changed_cb, bus); - - bus->name_notify_enabled = true; - } - - return true; -} - -struct name_request { - l_dbus_name_acquire_func_t callback; - void *user_data; - struct l_dbus *dbus; -}; - -enum dbus_name_flag { - DBUS_NAME_FLAG_ALLOW_REPLACEMENT = 0x1, - DBUS_NAME_FLAG_REPLACE_EXISTING = 0x2, - DBUS_NAME_FLAG_DO_NOT_QUEUE = 0x4, -}; - -enum dbus_name_reply { - DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 1, - DBUS_REQUEST_NAME_REPLY_IN_QUEUE = 2, - DBUS_REQUEST_NAME_REPLY_EXISTS = 3, - DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER = 4, -}; - -static void request_name_reply_cb(struct l_dbus_message *reply, void *user_data) -{ - struct name_request *req = user_data; - bool success = false, queued = false; - uint32_t retval; - - if (!req->callback) - return; - - /* No name owner yet */ - if (l_dbus_message_is_error(reply)) - goto call_back; - - /* Shouldn't happen */ - if (!l_dbus_message_get_arguments(reply, "u", &retval)) - goto call_back; - - success = (retval == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) || - (retval == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER) || - (retval == DBUS_REQUEST_NAME_REPLY_IN_QUEUE); - queued = (retval == DBUS_REQUEST_NAME_REPLY_IN_QUEUE); - -call_back: - req->callback(req->dbus, success, queued, req->user_data); -} - -static uint32_t classic_name_acquire(struct l_dbus *dbus, const char *name, - bool allow_replacement, - bool replace_existing, bool queue, - l_dbus_name_acquire_func_t callback, - void *user_data) -{ - struct name_request *req; - struct l_dbus_message *message; - uint32_t flags = 0; - - req = l_new(struct name_request, 1); - req->dbus = dbus; - req->user_data = user_data; - req->callback = callback; - - message = l_dbus_message_new_method_call(dbus, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - L_DBUS_INTERFACE_DBUS, - "RequestName"); - - if (allow_replacement) - flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT; - - if (replace_existing) - flags |= DBUS_NAME_FLAG_REPLACE_EXISTING; - - if (!queue) - flags |= DBUS_NAME_FLAG_DO_NOT_QUEUE; - - l_dbus_message_set_arguments(message, "su", name, flags); - - return send_message(dbus, false, message, request_name_reply_cb, - req, free); -} - -static const struct l_dbus_ops classic_ops = { - .version = 1, - .send_message = classic_send_message, - .recv_message = classic_recv_message, - .free = classic_free, - .name_ops = { - .get_name_owner = classic_get_name_owner, - }, - .filter_ops = { - .add_match = classic_add_match, - .remove_match = classic_remove_match, - }, - .name_acquire = classic_name_acquire, -}; - -static struct l_dbus *setup_dbus1(int fd, const char *guid) -{ - static const unsigned char creds = 0x00; - char uid[6], hexuid[12], *ptr = hexuid; - struct l_dbus *dbus; - struct l_dbus_classic *classic; - ssize_t written; - unsigned int i; - - if (snprintf(uid, sizeof(uid), "%d", geteuid()) < 1) { - close(fd); - return NULL; - } - - for (i = 0; i < strlen(uid); i++) - ptr += sprintf(ptr, "%02x", uid[i]); - - /* Send special credentials-passing nul byte */ - written = L_TFR(send(fd, &creds, 1, 0)); - if (written < 1) { - close(fd); - return NULL; - } - - classic = l_new(struct l_dbus_classic, 1); - dbus = &classic->super; - dbus->driver = &classic_ops; - - classic->match_strings = l_hashmap_new(); - - dbus_init(dbus, fd); - dbus->guid = l_strdup(guid); - - classic->auth_command = l_strdup_printf("AUTH EXTERNAL %s\r\n", hexuid); - classic->auth_state = WAITING_FOR_OK; - - dbus->negotiate_unix_fd = true; - dbus->support_unix_fd = false; - - l_io_set_read_handler(dbus->io, auth_read_handler, dbus, NULL); - l_io_set_write_handler(dbus->io, auth_write_handler, dbus, NULL); - - return dbus; -} - -static struct l_dbus *setup_unix(char *params) -{ - char *path = NULL, *guid = NULL; - bool abstract = false; - struct sockaddr_un addr; - size_t len; - int fd; - - while (params) { - char *key = strsep(¶ms, ","); - char *value; - - if (!key) - break; - - value = strchr(key, '='); - if (!value) - continue; - - *value++ = '\0'; - - if (!strcmp(key, "path")) { - path = value; - abstract = false; - } else if (!strcmp(key, "abstract")) { - path = value; - abstract = true; - } else if (!strcmp(key, "guid")) - guid = value; - } - - if (!path) - return NULL; - - fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (fd < 0) - return NULL; - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - - len = strlen(path); - - if (abstract) { - if (len > sizeof(addr.sun_path) - 1) { - close(fd); - return NULL; - } - - addr.sun_path[0] = '\0'; - strncpy(addr.sun_path + 1, path, sizeof(addr.sun_path) - 2); - len++; - } else { - if (len > sizeof(addr.sun_path)) { - close(fd); - return NULL; - } - - strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); - } - - if (connect(fd, (struct sockaddr *) &addr, - sizeof(addr.sun_family) + len) < 0) { - close(fd); - return NULL; - } - - return setup_dbus1(fd, guid); -} - -static struct l_dbus *setup_address(const char *address) -{ - struct l_dbus *dbus = NULL; - char *address_copy; - - address_copy = strdupa(address); - - while (address_copy) { - char *transport = strsep(&address_copy, ";"); - char *params; - - if (!transport) - break; - - params = strchr(transport, ':'); - if (params) - *params++ = '\0'; - - if (!strcmp(transport, "unix")) { - /* Function will modify params string */ - dbus = setup_unix(params); - break; - } - } - - return dbus; -} - -LIB_EXPORT struct l_dbus *l_dbus_new(const char *address) -{ - if (unlikely(!address)) - return NULL; - - return setup_address(address); -} - -LIB_EXPORT struct l_dbus *l_dbus_new_default(enum l_dbus_bus bus) -{ - const char *address; - - switch (bus) { - case L_DBUS_SYSTEM_BUS: - address = getenv("DBUS_SYSTEM_BUS_ADDRESS"); - if (!address) - address = DEFAULT_SYSTEM_BUS_ADDRESS; - break; - case L_DBUS_SESSION_BUS: - address = getenv("DBUS_SESSION_BUS_ADDRESS"); - if (!address) - return NULL; - break; - default: - return NULL; - } - - return setup_address(address); -} - -LIB_EXPORT void l_dbus_destroy(struct l_dbus *dbus) -{ - if (unlikely(!dbus)) - return; - - if (dbus->ready_destroy) - dbus->ready_destroy(dbus->ready_data); - - _dbus_filter_free(dbus->filter); - - _dbus_name_cache_free(dbus->name_cache); - - l_hashmap_destroy(dbus->signal_list, signal_list_destroy); - l_hashmap_destroy(dbus->message_list, message_list_destroy); - l_queue_destroy(dbus->message_queue, message_queue_destroy); - - l_io_destroy(dbus->io); - - if (dbus->disconnect_destroy) - dbus->disconnect_destroy(dbus->disconnect_data); - - if (dbus->debug_destroy) - dbus->debug_destroy(dbus->debug_data); - - l_free(dbus->guid); - l_free(dbus->unique_name); - - _dbus_object_tree_free(dbus->tree); - - dbus->driver->free(dbus); -} - -LIB_EXPORT bool l_dbus_set_ready_handler(struct l_dbus *dbus, - l_dbus_ready_func_t function, - void *user_data, l_dbus_destroy_func_t destroy) -{ - if (unlikely(!dbus)) - return false; - - if (dbus->ready_destroy) - dbus->ready_destroy(dbus->ready_data); - - dbus->ready_handler = function; - dbus->ready_destroy = destroy; - dbus->ready_data = user_data; - - return true; -} - -LIB_EXPORT bool l_dbus_set_disconnect_handler(struct l_dbus *dbus, - l_dbus_disconnect_func_t function, - void *user_data, l_dbus_destroy_func_t destroy) -{ - if (unlikely(!dbus)) - return false; - - if (dbus->disconnect_destroy) - dbus->disconnect_destroy(dbus->disconnect_data); - - dbus->disconnect_handler = function; - dbus->disconnect_destroy = destroy; - dbus->disconnect_data = user_data; - - return true; -} - -LIB_EXPORT bool l_dbus_set_debug(struct l_dbus *dbus, - l_dbus_debug_func_t function, - void *user_data, l_dbus_destroy_func_t destroy) -{ - if (unlikely(!dbus)) - return false; - - if (dbus->debug_destroy) - dbus->debug_destroy(dbus->debug_data); - - dbus->debug_handler = function; - dbus->debug_destroy = destroy; - dbus->debug_data = user_data; - - /* l_io_set_debug(dbus->io, function, user_data, NULL); */ - - return true; -} - -LIB_EXPORT uint32_t l_dbus_send_with_reply(struct l_dbus *dbus, - struct l_dbus_message *message, - l_dbus_message_func_t function, - void *user_data, - l_dbus_destroy_func_t destroy) -{ - if (unlikely(!dbus || !message)) - return 0; - - return send_message(dbus, false, message, function, user_data, destroy); -} - -LIB_EXPORT uint32_t l_dbus_send(struct l_dbus *dbus, - struct l_dbus_message *message) -{ - if (unlikely(!dbus || !message)) - return 0; - - return send_message(dbus, false, message, NULL, NULL, NULL); -} - -static bool remove_entry(void *data, void *user_data) -{ - struct message_callback *callback = data; - uint32_t serial = L_PTR_TO_UINT(user_data); - - if (callback->serial == serial) { - message_queue_destroy(callback); - return true; - } - - return false; -} - -LIB_EXPORT bool l_dbus_cancel(struct l_dbus *dbus, uint32_t serial) -{ - struct message_callback *callback; - unsigned int count; - - if (unlikely(!dbus || !serial)) - return false; - - callback = l_hashmap_remove(dbus->message_list, L_UINT_TO_PTR(serial)); - if (callback) { - message_queue_destroy(callback); - return true; - } - - count = l_queue_foreach_remove(dbus->message_queue, remove_entry, - L_UINT_TO_PTR(serial)); - if (!count) - return false; - - return true; -} - -LIB_EXPORT unsigned int l_dbus_register(struct l_dbus *dbus, - l_dbus_message_func_t function, - void *user_data, l_dbus_destroy_func_t destroy) -{ - struct signal_callback *callback; - - if (unlikely(!dbus)) - return 0; - - callback = l_new(struct signal_callback, 1); - - callback->id = dbus->next_id++; - callback->callback = function; - callback->destroy = destroy; - callback->user_data = user_data; - - l_hashmap_insert(dbus->signal_list, - L_UINT_TO_PTR(callback->id), callback); - - return callback->id; -} - -LIB_EXPORT bool l_dbus_unregister(struct l_dbus *dbus, unsigned int id) -{ - struct signal_callback *callback; - - if (unlikely(!dbus || !id)) - return false; - - callback = l_hashmap_remove(dbus->signal_list, L_UINT_TO_PTR(id)); - if (!callback) - return false; - - signal_list_destroy(callback); - - return true; -} - -LIB_EXPORT uint32_t l_dbus_method_call(struct l_dbus *dbus, - const char *destination, const char *path, - const char *interface, const char *method, - l_dbus_message_func_t setup, - l_dbus_message_func_t function, - void *user_data, l_dbus_destroy_func_t destroy) -{ - struct l_dbus_message *message; - - if (unlikely(!dbus)) - return 0; - - message = l_dbus_message_new_method_call(dbus, destination, path, - interface, method); - - if (setup) - setup(message, user_data); - else - l_dbus_message_set_arguments(message, ""); - - return send_message(dbus, false, message, function, user_data, destroy); -} - -uint8_t _dbus_get_version(struct l_dbus *dbus) -{ - return dbus->driver->version; -} - -int _dbus_get_fd(struct l_dbus *dbus) -{ - return l_io_get_fd(dbus->io); -} - -struct _dbus_object_tree *_dbus_get_tree(struct l_dbus *dbus) -{ - return dbus->tree; -} - -/** - * l_dbus_register_interface: - * @dbus: D-Bus connection as returned by @l_dbus_new* - * @interface: interface name string - * @setup_func: function that sets up the methods, signals and properties by - * using the #dbus-service.h API. - * @destroy: optional destructor to be called every time an instance of this - * interface is being removed from an object on this bus. - * @handle_old_style_properties: whether to automatically handle SetProperty and - * GetProperties for any properties registered by - * @setup_func. - * - * Registers an interface. If successful the interface can then be added - * to any number of objects with @l_dbus_object_add_interface. - * - * Returns: whether the interface was successfully registered - **/ -LIB_EXPORT bool l_dbus_register_interface(struct l_dbus *dbus, - const char *interface, - l_dbus_interface_setup_func_t setup_func, - l_dbus_destroy_func_t destroy, - bool handle_old_style_properties) -{ - if (unlikely(!dbus)) - return false; - - if (unlikely(!dbus->tree)) - return false; - - return _dbus_object_tree_register_interface(dbus->tree, interface, - setup_func, destroy, - handle_old_style_properties); -} - -LIB_EXPORT bool l_dbus_unregister_interface(struct l_dbus *dbus, - const char *interface) -{ - if (unlikely(!dbus)) - return false; - - if (unlikely(!dbus->tree)) - return false; - - return _dbus_object_tree_unregister_interface(dbus->tree, interface); -} - -/** - * l_dbus_register_object: - * @dbus: D-Bus connection - * @path: new object path - * @user_data: user pointer to be passed to @destroy if any - * @destroy: optional destructor to be called when object dropped from the tree - * @...: NULL-terminated list of 0 or more interfaces to be present on the - * object from the moment of creation. For every interface the interface - * name string is expected followed by the @user_data pointer same as - * would be passed as @l_dbus_object_add_interface's last two parameters. - * - * Create a new D-Bus object on the tree visible to D-Bus peers. For example: - * success = l_dbus_register_object(bus, "/org/example/ExampleManager", - * NULL, NULL, - * "org.example.Manager", - * manager_data, - * NULL); - * - * Returns: whether the object path was successfully registered - **/ -LIB_EXPORT bool l_dbus_register_object(struct l_dbus *dbus, const char *path, - void *user_data, - l_dbus_destroy_func_t destroy, ...) -{ - va_list args; - const char *interface; - void *if_user_data; - bool r = true;; - - if (unlikely(!dbus)) - return false; - - if (unlikely(!dbus->tree)) - return false; - - if (!_dbus_object_tree_new_object(dbus->tree, path, user_data, destroy)) - return false; - - va_start(args, destroy); - while ((interface = va_arg(args, const char *))) { - if_user_data = va_arg(args, void *); - - if (!_dbus_object_tree_add_interface(dbus->tree, path, - interface, - if_user_data)) { - _dbus_object_tree_object_destroy(dbus->tree, path); - r = false; - - break; - } - } - va_end(args); - - return r; -} - -LIB_EXPORT bool l_dbus_unregister_object(struct l_dbus *dbus, - const char *object) -{ - if (unlikely(!dbus)) - return false; - - if (unlikely(!dbus->tree)) - return false; - - return _dbus_object_tree_object_destroy(dbus->tree, object); -} - -/** - * l_dbus_object_add_interface: - * @dbus: D-Bus connection - * @object: object path as passed to @l_dbus_register_object - * @interface: interface name as passed to @l_dbus_register_interface - * @user_data: user data pointer to be passed to any method and property - * callbacks provided by the @setup_func and to the @destroy - * callback as passed to @l_dbus_register_interface - * - * Creates an instance of given interface at the given path in the - * connection's object tree. If no object was registered at this path - * before @l_dbus_register_object gets called automatically. - * - * The addition of an interface to the object may trigger a query of - * all the properties on this interface and - * #org.freedesktop.DBus.ObjectManager.InterfacesAdded signals. - * - * Returns: whether the interface was successfully added. - **/ -LIB_EXPORT bool l_dbus_object_add_interface(struct l_dbus *dbus, - const char *object, - const char *interface, - void *user_data) -{ - if (unlikely(!dbus)) - return false; - - if (unlikely(!dbus->tree)) - return false; - - return _dbus_object_tree_add_interface(dbus->tree, object, interface, - user_data); -} - -LIB_EXPORT bool l_dbus_object_remove_interface(struct l_dbus *dbus, - const char *object, - const char *interface) -{ - if (unlikely(!dbus)) - return false; - - if (unlikely(!dbus->tree)) - return false; - - return _dbus_object_tree_remove_interface(dbus->tree, object, - interface); -} - -LIB_EXPORT void *l_dbus_object_get_data(struct l_dbus *dbus, const char *object, - const char *interface) -{ - if (unlikely(!dbus)) - return false; - - if (unlikely(!dbus->tree)) - return false; - - return _dbus_object_tree_get_interface_data(dbus->tree, object, - interface); -} - -LIB_EXPORT bool l_dbus_object_manager_enable(struct l_dbus *dbus, - const char *root) -{ - if (unlikely(!dbus)) - return false; - - if (unlikely(!dbus->tree)) - return false; - - return _dbus_object_tree_add_interface(dbus->tree, root, - L_DBUS_INTERFACE_OBJECT_MANAGER, - dbus); -} - -LIB_EXPORT unsigned int l_dbus_add_disconnect_watch(struct l_dbus *dbus, - const char *name, - l_dbus_watch_func_t disconnect_func, - void *user_data, - l_dbus_destroy_func_t destroy) -{ - return l_dbus_add_service_watch(dbus, name, NULL, disconnect_func, - user_data, destroy); -} - -LIB_EXPORT unsigned int l_dbus_add_service_watch(struct l_dbus *dbus, - const char *name, - l_dbus_watch_func_t connect_func, - l_dbus_watch_func_t disconnect_func, - void *user_data, - l_dbus_destroy_func_t destroy) -{ - if (!name) - return 0; - - if (!dbus->name_cache) - dbus->name_cache = _dbus_name_cache_new(dbus, - &dbus->driver->name_ops); - - return _dbus_name_cache_add_watch(dbus->name_cache, name, connect_func, - disconnect_func, user_data, - destroy); -} - -LIB_EXPORT bool l_dbus_remove_watch(struct l_dbus *dbus, unsigned int id) -{ - if (!dbus->name_cache) - return false; - - return _dbus_name_cache_remove_watch(dbus->name_cache, id); -} - -/** - * l_dbus_add_signal_watch: - * @dbus: D-Bus connection - * @sender: bus name to match the signal sender against or NULL to - * match any sender - * @path: object path to match the signal path against or NULL to - * match any path - * @interface: interface name to match the signal interface against - * or NULL to match any interface - * @member: name to match the signal name against or NULL to match any - * signal - * @...: a list of further conditions to be met by the signal followed - * by three more mandatory parameters: - * enum l_dbus_match_type list_end_marker, - * l_dbus_message_func callback, - * void *user_data, - * The value L_DBUS_MATCH_NONE must be passed as the end of list - * marker, followed by the signal match callback and user_data. - * In the list, every condition is a pair of parameters: - * enum l_dbus_match_type match_type, const char *value. - * - * Subscribe to a group of signals based on a set of conditions that - * compare the signal's header fields and string arguments against given - * values. For example: - * signal_id = l_dbus_add_signal_watch(bus, "org.example", "/" - * "org.example.Manager", - * "PropertyChanged", - * L_DBUS_MATCH_ARGUMENT(0), - * "ExampleProperty", - * L_DBUS_MATCH_NONE - * manager_property_change_cb, - * NULL); - * - * Returns: a non-zero signal filter identifier that can be passed to - * l_dbus_remove_signal_watch to remove this filter rule, or - * zero on failure. - **/ -LIB_EXPORT unsigned int l_dbus_add_signal_watch(struct l_dbus *dbus, - const char *sender, - const char *path, - const char *interface, - const char *member, ...) -{ - struct _dbus_filter_condition *rule; - int rule_len; - va_list args; - const char *value; - l_dbus_message_func_t signal_func; - enum l_dbus_match_type type; - void *user_data; - unsigned int id; - - va_start(args, member); - - rule_len = 0; - while ((type = va_arg(args, enum l_dbus_match_type)) != - L_DBUS_MATCH_NONE) - rule_len++; - - va_end(args); - - rule = l_new(struct _dbus_filter_condition, rule_len + 5); - - rule_len = 0; - - rule[rule_len].type = L_DBUS_MATCH_TYPE; - rule[rule_len++].value = "signal"; - - if (sender) { - rule[rule_len].type = L_DBUS_MATCH_SENDER; - rule[rule_len++].value = sender; - } - - if (path) { - rule[rule_len].type = L_DBUS_MATCH_PATH; - rule[rule_len++].value = path; - } - - if (interface) { - rule[rule_len].type = L_DBUS_MATCH_INTERFACE; - rule[rule_len++].value = interface; - } - - if (member) { - rule[rule_len].type = L_DBUS_MATCH_MEMBER; - rule[rule_len++].value = member; - } - - va_start(args, member); - - while (true) { - type = va_arg(args, enum l_dbus_match_type); - if (type == L_DBUS_MATCH_NONE) - break; - - value = va_arg(args, const char *); - - rule[rule_len].type = type; - rule[rule_len++].value = value; - } - - signal_func = va_arg(args, l_dbus_message_func_t); - user_data = va_arg(args, void *); - - va_end(args); - - if (!dbus->filter) { - if (!dbus->name_cache) - dbus->name_cache = _dbus_name_cache_new(dbus, - &dbus->driver->name_ops); - - dbus->filter = _dbus_filter_new(dbus, - &dbus->driver->filter_ops, - dbus->name_cache); - } - - id = _dbus_filter_add_rule(dbus->filter, rule, rule_len, - signal_func, user_data); - - l_free(rule); - - return id; -} - -LIB_EXPORT bool l_dbus_remove_signal_watch(struct l_dbus *dbus, unsigned int id) -{ - if (!dbus->filter) - return false; - - return _dbus_filter_remove_rule(dbus->filter, id); -} - -/** - * l_dbus_name_acquire: - * @dbus: D-Bus connection - * @name: Well-known bus name to be acquired - * @allow_replacement: Whether to allow another peer's name request to - * take the name ownership away from this connection - * @replace_existing: Whether to allow D-Bus to take the name's ownership - * away from another peer in case the name is already - * owned and allows replacement. Ignored if name is - * currently free. - * @queue: Whether to allow the name request to be queued by D-Bus in - * case it cannot be acquired now, rather than to return a failure. - * @callback: Callback to receive the request result when done. - * - * Acquire a well-known bus name (service name) on the bus. - * - * Returns: a non-zero request serial that can be passed to l_dbus_cancel - * while waiting for the callback or zero if the callback has - * has happened while l_dbus_name_acquire was running. - **/ -LIB_EXPORT uint32_t l_dbus_name_acquire(struct l_dbus *dbus, const char *name, - bool allow_replacement, bool replace_existing, - bool queue, l_dbus_name_acquire_func_t callback, - void *user_data) -{ - return dbus->driver->name_acquire(dbus, name, allow_replacement, - replace_existing, queue, - callback, user_data); -} diff --git a/ell/dbus.h b/ell/dbus.h deleted file mode 100644 index cbfb0b0..0000000 --- a/ell/dbus.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_DBUS_H -#define __ELL_DBUS_H - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define L_DBUS_INTERFACE_DBUS "org.freedesktop.DBus" -#define L_DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable" -#define L_DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties" -#define L_DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager" - -enum l_dbus_bus { - L_DBUS_SYSTEM_BUS, - L_DBUS_SESSION_BUS, -}; - -enum l_dbus_match_type { - L_DBUS_MATCH_NONE = 0, - L_DBUS_MATCH_TYPE, - L_DBUS_MATCH_SENDER, - L_DBUS_MATCH_PATH, - L_DBUS_MATCH_INTERFACE, - L_DBUS_MATCH_MEMBER, - L_DBUS_MATCH_ARG0, -}; - -#define L_DBUS_MATCH_ARGUMENT(i) (L_DBUS_MATCH_ARG0 + (i)) - -struct l_dbus; -struct l_dbus_interface; -struct l_dbus_message_builder; - -typedef void (*l_dbus_ready_func_t) (void *user_data); -typedef void (*l_dbus_disconnect_func_t) (void *user_data); - -typedef void (*l_dbus_debug_func_t) (const char *str, void *user_data); -typedef void (*l_dbus_destroy_func_t) (void *user_data); -typedef void (*l_dbus_interface_setup_func_t) (struct l_dbus_interface *); - -typedef void (*l_dbus_watch_func_t) (struct l_dbus *dbus, void *user_data); - -typedef void (*l_dbus_name_acquire_func_t) (struct l_dbus *dbus, bool success, - bool queued, void *user_data); - -struct l_dbus *l_dbus_new(const char *address); -struct l_dbus *l_dbus_new_default(enum l_dbus_bus bus); -void l_dbus_destroy(struct l_dbus *dbus); - -bool l_dbus_set_ready_handler(struct l_dbus *dbus, l_dbus_ready_func_t function, - void *user_data, l_dbus_destroy_func_t destroy); -bool l_dbus_set_disconnect_handler(struct l_dbus *dbus, - l_dbus_disconnect_func_t function, - void *user_data, l_dbus_destroy_func_t destroy); - -bool l_dbus_set_debug(struct l_dbus *dbus, l_dbus_debug_func_t function, - void *user_data, l_dbus_destroy_func_t destroy); - -struct l_dbus_message; - -struct l_dbus_message_iter { - struct l_dbus_message *message; - const char *sig_start; - uint8_t sig_len; - uint8_t sig_pos; - const void *data; - size_t len; - size_t pos; - char container_type; - const void *offsets; -}; - -struct l_dbus_message *l_dbus_message_new_method_call(struct l_dbus *dbus, - const char *destination, - const char *path, - const char *interface, - const char *method); - -struct l_dbus_message *l_dbus_message_new_signal(struct l_dbus *dbus, - const char *path, - const char *interface, - const char *name); - -struct l_dbus_message *l_dbus_message_new_method_return( - struct l_dbus_message *method_call); - -struct l_dbus_message *l_dbus_message_new_error_valist( - struct l_dbus_message *method_call, - const char *name, - const char *format, va_list args); -struct l_dbus_message *l_dbus_message_new_error( - struct l_dbus_message *method_call, - const char *name, - const char *format, ...) - __attribute__((format(printf, 3, 4))); - -struct l_dbus_message *l_dbus_message_ref(struct l_dbus_message *message); -void l_dbus_message_unref(struct l_dbus_message *message); - -const char *l_dbus_message_get_path(struct l_dbus_message *message); -const char *l_dbus_message_get_interface(struct l_dbus_message *message); -const char *l_dbus_message_get_member(struct l_dbus_message *message); -const char *l_dbus_message_get_destination(struct l_dbus_message *message); -const char *l_dbus_message_get_sender(struct l_dbus_message *message); -const char *l_dbus_message_get_signature(struct l_dbus_message *message); - -bool l_dbus_message_set_no_reply(struct l_dbus_message *message, bool on); -bool l_dbus_message_get_no_reply(struct l_dbus_message *message); - -bool l_dbus_message_set_no_autostart(struct l_dbus_message *message, bool on); -bool l_dbus_message_get_no_autostart(struct l_dbus_message *message); - -typedef void (*l_dbus_message_func_t) (struct l_dbus_message *message, - void *user_data); - -uint32_t l_dbus_send_with_reply(struct l_dbus *dbus, - struct l_dbus_message *message, - l_dbus_message_func_t function, - void *user_data, l_dbus_destroy_func_t destroy); -uint32_t l_dbus_send(struct l_dbus *dbus, - struct l_dbus_message *message); -bool l_dbus_cancel(struct l_dbus *dbus, uint32_t serial); - -unsigned int l_dbus_register(struct l_dbus *dbus, - l_dbus_message_func_t function, - void *user_data, l_dbus_destroy_func_t destroy); -bool l_dbus_unregister(struct l_dbus *dbus, unsigned int id); - -uint32_t l_dbus_method_call(struct l_dbus *dbus, - const char *destination, const char *path, - const char *interface, const char *method, - l_dbus_message_func_t setup, - l_dbus_message_func_t function, - void *user_data, l_dbus_destroy_func_t destroy); - -bool l_dbus_message_is_error(struct l_dbus_message *message); -bool l_dbus_message_get_error(struct l_dbus_message *message, - const char **name, const char **text); -bool l_dbus_message_get_arguments(struct l_dbus_message *message, - const char *signature, ...); -bool l_dbus_message_get_arguments_valist(struct l_dbus_message *message, - const char *signature, va_list args); - -bool l_dbus_message_iter_next_entry(struct l_dbus_message_iter *iter, ...); -bool l_dbus_message_iter_get_variant(struct l_dbus_message_iter *iter, - const char *signature, ...); -bool l_dbus_message_iter_get_fixed_array(struct l_dbus_message_iter *iter, - void *out, uint32_t *n_elem); - -bool l_dbus_message_set_arguments(struct l_dbus_message *message, - const char *signature, ...); -bool l_dbus_message_set_arguments_valist(struct l_dbus_message *message, - const char *signature, va_list args); - -struct l_dbus_message_builder *l_dbus_message_builder_new( - struct l_dbus_message *message); -void l_dbus_message_builder_destroy(struct l_dbus_message_builder *builder); - -bool l_dbus_message_builder_append_basic(struct l_dbus_message_builder *builder, - char type, const void *value); - -bool l_dbus_message_builder_enter_container( - struct l_dbus_message_builder *builder, - char container_type, - const char *signature); -bool l_dbus_message_builder_leave_container( - struct l_dbus_message_builder *builder, - char container_type); - -bool l_dbus_message_builder_enter_struct(struct l_dbus_message_builder *builder, - const char *signature); -bool l_dbus_message_builder_leave_struct( - struct l_dbus_message_builder *builder); - -bool l_dbus_message_builder_enter_dict(struct l_dbus_message_builder *builder, - const char *signature); -bool l_dbus_message_builder_leave_dict(struct l_dbus_message_builder *builder); - -bool l_dbus_message_builder_enter_array(struct l_dbus_message_builder *builder, - const char *signature); -bool l_dbus_message_builder_leave_array(struct l_dbus_message_builder *builder); - -bool l_dbus_message_builder_enter_variant( - struct l_dbus_message_builder *builder, - const char *signature); -bool l_dbus_message_builder_leave_variant( - struct l_dbus_message_builder *builder); - -bool l_dbus_message_builder_append_from_iter( - struct l_dbus_message_builder *builder, - struct l_dbus_message_iter *from); - -bool l_dbus_message_builder_append_from_valist( - struct l_dbus_message_builder *builder, - const char *signature, va_list args); - -struct l_dbus_message *l_dbus_message_builder_finalize( - struct l_dbus_message_builder *builder); - -bool l_dbus_register_interface(struct l_dbus *dbus, const char *interface, - l_dbus_interface_setup_func_t setup_func, - l_dbus_destroy_func_t destroy, - bool handle_old_style_properties); -bool l_dbus_unregister_interface(struct l_dbus *dbus, const char *interface); - -bool l_dbus_register_object(struct l_dbus *dbus, const char *path, - void *user_data, l_dbus_destroy_func_t destroy, - ...); -bool l_dbus_unregister_object(struct l_dbus *dbus, const char *object); - -bool l_dbus_object_add_interface(struct l_dbus *dbus, const char *object, - const char *interface, void *user_data); -bool l_dbus_object_remove_interface(struct l_dbus *dbus, const char *object, - const char *interface); -void *l_dbus_object_get_data(struct l_dbus *dbus, const char *object, - const char *interface); - -bool l_dbus_object_manager_enable(struct l_dbus *dbus, const char *root); - -unsigned int l_dbus_add_service_watch(struct l_dbus *dbus, - const char *name, - l_dbus_watch_func_t connect_func, - l_dbus_watch_func_t disconnect_func, - void *user_data, - l_dbus_destroy_func_t destroy); - -unsigned int l_dbus_add_disconnect_watch(struct l_dbus *dbus, - const char *name, - l_dbus_watch_func_t disconnect_func, - void *user_data, - l_dbus_destroy_func_t destroy); -bool l_dbus_remove_watch(struct l_dbus *dbus, unsigned int id); - -unsigned int l_dbus_add_signal_watch(struct l_dbus *dbus, - const char *sender, - const char *path, - const char *interface, - const char *member, ...); -bool l_dbus_remove_signal_watch(struct l_dbus *dbus, unsigned int id); - -uint32_t l_dbus_name_acquire(struct l_dbus *dbus, const char *name, - bool allow_replacement, bool replace_existing, - bool queue, l_dbus_name_acquire_func_t callback, - void *user_data); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_DBUS_H */ diff --git a/ell/dhcp-lease.c b/ell/dhcp-lease.c deleted file mode 100644 index a48cfa4..0000000 --- a/ell/dhcp-lease.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "private.h" -#include "dhcp.h" -#include "dhcp-private.h" - -struct l_dhcp_lease *_dhcp_lease_new(void) -{ - struct l_dhcp_lease *ret = l_new(struct l_dhcp_lease, 1); - - return ret; -} - -void _dhcp_lease_free(struct l_dhcp_lease *lease) -{ - if (!lease) - return; - - l_free(lease->dns); - l_free(lease); -} - -struct l_dhcp_lease *_dhcp_lease_parse_options(struct dhcp_message_iter *iter) -{ - struct l_dhcp_lease *lease = _dhcp_lease_new(); - uint8_t t, l; - const void *v; - - while (_dhcp_message_iter_next(iter, &t, &l, &v)) { - switch (t) { - case L_DHCP_OPTION_IP_ADDRESS_LEASE_TIME: - if (l == 4) - lease->lifetime = l_get_be32(v); - break; - case L_DHCP_OPTION_SERVER_IDENTIFIER: - if (l == 4) - lease->server_address = l_get_u32(v); - break; - case L_DHCP_OPTION_SUBNET_MASK: - if (l == 4) - lease->subnet_mask = l_get_u32(v); - break; - case L_DHCP_OPTION_ROUTER: - if (l == 4) - lease->router = l_get_u32(v); - break; - case L_DHCP_OPTION_RENEWAL_T1_TIME: - if (l == 4) - lease->t1 = l_get_be32(v); - break; - case L_DHCP_OPTION_REBINDING_T2_TIME: - if (l == 4) - lease->t2 = l_get_be32(v); - break; - case L_DHCP_OPTION_BROADCAST_ADDRESS: - if (l == 4) - lease->broadcast = l_get_u32(v); - break; - case L_DHCP_OPTION_DOMAIN_NAME_SERVER: - if (l >= 4 && !(l % 4)) { - unsigned i = 0; - - lease->dns = l_new(uint32_t, l / 4 + 1); - - while (l >= 4) { - lease->dns[i] = l_get_u32(v + i * 4); - l -= 4; - - if (lease->dns[i]) - i++; - } - } - break; - default: - break; - } - } - - if (!lease->server_address || !lease->lifetime) - goto error; - - if (lease->lifetime < 10) - goto error; - - if (!lease->t1) - lease->t1 = lease->lifetime / 2; - - if (!lease->t2) - lease->t2 = lease->lifetime * 7 / 8; - - if (lease->t1 > lease->t2) - goto error; - - if (lease->t2 > lease->lifetime) - goto error; - - return lease; -error: - l_free(lease); - return NULL; -} - -static inline char *get_ip(uint32_t ip) -{ - struct in_addr addr; - - if (ip == 0) - return NULL; - - addr.s_addr = ip; - return l_strdup(inet_ntoa(addr)); -} - -LIB_EXPORT char *l_dhcp_lease_get_address(const struct l_dhcp_lease *lease) -{ - if (unlikely(!lease)) - return NULL; - - return get_ip(lease->address); -} - -LIB_EXPORT char *l_dhcp_lease_get_gateway(const struct l_dhcp_lease *lease) -{ - if (unlikely(!lease)) - return NULL; - - return get_ip(lease->router); -} - -LIB_EXPORT char *l_dhcp_lease_get_netmask(const struct l_dhcp_lease *lease) -{ - if (unlikely(!lease)) - return NULL; - - return get_ip(lease->subnet_mask); -} - -LIB_EXPORT char *l_dhcp_lease_get_broadcast(const struct l_dhcp_lease *lease) -{ - if (unlikely(!lease)) - return NULL; - - return get_ip(lease->broadcast); -} - -LIB_EXPORT char *l_dhcp_lease_get_server_id(const struct l_dhcp_lease *lease) -{ - if (unlikely(!lease)) - return NULL; - - return get_ip(lease->server_address); -} - -LIB_EXPORT char **l_dhcp_lease_get_dns(const struct l_dhcp_lease *lease) -{ - unsigned i; - char **dns_list; - - if (unlikely(!lease)) - return NULL; - - if (!lease->dns) - return NULL; - - for (i = 0; lease->dns[i]; i++) - ; - - dns_list = l_new(char *, i + 1); - - for (i = 0; lease->dns[i]; i++) - dns_list[i] = get_ip(lease->dns[i]); - - return dns_list; -} - -LIB_EXPORT uint32_t l_dhcp_lease_get_t1(const struct l_dhcp_lease *lease) -{ - if (unlikely(!lease)) - return 0; - - return lease->t1; -} - -LIB_EXPORT uint32_t l_dhcp_lease_get_t2(const struct l_dhcp_lease *lease) -{ - if (unlikely(!lease)) - return 0; - - return lease->t2; -} - -LIB_EXPORT uint32_t l_dhcp_lease_get_lifetime(const struct l_dhcp_lease *lease) -{ - if (unlikely(!lease)) - return 0; - - return lease->lifetime; -} diff --git a/ell/dhcp-private.h b/ell/dhcp-private.h deleted file mode 100644 index 6554fc6..0000000 --- a/ell/dhcp-private.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -struct l_dhcp_client; - -enum { - DHCP_PORT_SERVER = 67, - DHCP_PORT_CLIENT = 68, -}; - -/* RFC 2131, Table 1 */ -enum dhcp_op_code { - DHCP_OP_CODE_BOOTREQUEST = 1, - DHCP_OP_CODE_BOOTREPLY = 2, -}; - -#define DHCP_MAGIC 0x63825363 - -/* RFC 2131, Figure 1 */ -struct dhcp_message { - uint8_t op; - uint8_t htype; - uint8_t hlen; - uint8_t hops; - __be32 xid; - __be16 secs; - __be16 flags; - uint32_t ciaddr; - uint32_t yiaddr; - uint32_t siaddr; - uint32_t giaddr; - uint8_t chaddr[16]; - uint8_t sname[64]; - uint8_t file[128]; - __be32 magic; - uint8_t options[0]; -} __attribute__ ((packed)); - -struct dhcp_message_iter { - const struct dhcp_message *message; - size_t message_len; - const uint8_t *options; - uint16_t pos; - uint16_t max; - bool can_overload : 1; - bool overload_sname : 1; - bool overload_file : 1; -}; - -const char *_dhcp_message_type_to_string(uint8_t type); -const char *_dhcp_option_to_string(uint8_t option); - -uint16_t _dhcp_checksum(const void *buf, size_t len); -uint16_t _dhcp_checksumv(const struct iovec *iov, size_t iov_cnt); - -typedef void (*dhcp_transport_rx_cb_t)(const void *, size_t, void *); - -struct dhcp_transport { - int (*open)(struct dhcp_transport *s, uint32_t xid); - int (*broadcast)(struct dhcp_transport *transport, - uint32_t saddr, uint16_t sport, - uint32_t daddr, uint16_t dport, - const void *data, size_t len); - int (*bind)(struct dhcp_transport *transport, uint32_t saddr); - int (*send)(struct dhcp_transport *transport, - const struct sockaddr_in *dest, - const void *data, size_t len); - void (*close)(struct dhcp_transport *transport); - uint32_t ifindex; - dhcp_transport_rx_cb_t rx_cb; - void *rx_data; -}; - -struct dhcp_transport *_dhcp_default_transport_new(uint32_t ifindex, - const char *ifname, - uint16_t port); -void _dhcp_transport_free(struct dhcp_transport *transport); -void _dhcp_transport_set_rx_callback(struct dhcp_transport *transport, - dhcp_transport_rx_cb_t rx_cb, - void *userdata); - -bool _dhcp_message_iter_init(struct dhcp_message_iter *iter, - const struct dhcp_message *message, size_t len); -bool _dhcp_message_iter_next(struct dhcp_message_iter *iter, uint8_t *type, - uint8_t *len, const void **data); - -int _dhcp_option_append(uint8_t **buf, size_t *buflen, uint8_t code, - size_t optlen, const void *optval); - -bool _dhcp_client_set_transport(struct l_dhcp_client *client, - struct dhcp_transport *transport); -void _dhcp_client_override_xid(struct l_dhcp_client *client, uint32_t xid); - -struct l_dhcp_lease { - uint32_t address; - uint32_t server_address; - uint32_t subnet_mask; - uint32_t broadcast; - uint32_t lifetime; - uint32_t t1; - uint32_t t2; - uint32_t router; - uint32_t *dns; -}; - -struct l_dhcp_lease *_dhcp_lease_new(void); -void _dhcp_lease_free(struct l_dhcp_lease *lease); -struct l_dhcp_lease *_dhcp_lease_parse_options(struct dhcp_message_iter *iter); diff --git a/ell/dhcp-transport.c b/ell/dhcp-transport.c deleted file mode 100644 index 56db9dd..0000000 --- a/ell/dhcp-transport.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "io.h" -#include "util.h" -#include "private.h" -#include "dhcp-private.h" - -struct dhcp_default_transport { - struct dhcp_transport super; - struct l_io *io; - int udp_fd; - char ifname[IFNAMSIZ]; - uint16_t port; -}; - -struct dhcp_packet { - struct iphdr ip; - struct udphdr udp; - struct dhcp_message dhcp; -} __attribute__ ((packed)); - -/* - * For efficiency and simplicity of implementation, this function assumes that - * only the last buffer can have an odd number of bytes - */ -uint16_t _dhcp_checksumv(const struct iovec *iov, size_t iov_cnt) -{ - uint32_t sum = 0; - size_t i, j; - size_t len = 0; - - for (j = 0; j < iov_cnt; j++) { - const uint16_t *check = iov[j].iov_base; - - len += iov[j].iov_len; - - for (i = 0; i < iov[j].iov_len / 2; i++) - sum += check[i]; - } - - j--; - - if (len & 0x01) { - const uint8_t *odd = iov[j].iov_base; - sum += odd[iov[j].iov_len - 1]; - } - - while (sum >> 16) - sum = (sum & 0xffff) + (sum >> 16); - - return ~sum; -} - -uint16_t _dhcp_checksum(const void *buf, size_t len) -{ - struct iovec iov[1]; - - iov[0].iov_base = (void *) buf; - iov[0].iov_len = len; - - return _dhcp_checksumv(iov, 1); -} - -static bool _dhcp_default_transport_read_handler(struct l_io *io, - void *userdata) -{ - struct dhcp_default_transport *transport = userdata; - int fd = l_io_get_fd(io); - char buf[2048]; - ssize_t len; - struct dhcp_packet *p; - uint16_t c; - - len = read(fd, buf, sizeof(buf)); - if (len < 0) - return false; - - p = (struct dhcp_packet *) buf; - - if (len < L_BE16_TO_CPU(p->ip.tot_len)) - return true; - - if (len < (ssize_t) (L_BE16_TO_CPU(p->udp.len) + sizeof(struct iphdr))) - return true; - - c = p->ip.check; - p->ip.check = 0; - - if (c != _dhcp_checksum(&p->ip, sizeof(struct iphdr))) - return true; - - /* only compute if the UDP checksum is present, e.g. non-zero */ - if (p->udp.check) { - c = p->udp.check; - p->ip.check = p->udp.len; - p->ip.ttl = 0; - p->udp.check = 0; - - /* - * We fake the UDP pseudo-header by reusing bits of - * the IP header - */ - if (c != _dhcp_checksum(&p->ip.ttl, - L_BE16_TO_CPU(p->udp.len) + 12)) - return true; - } - - len -= sizeof(struct udphdr) - sizeof(struct iphdr); - - if (transport->super.rx_cb) - transport->super.rx_cb(&p->dhcp, len, transport->super.rx_data); - - return true; -} - -static void dhcp_set_ip_udp_headers(struct iphdr *ip, struct udphdr *udp, - uint32_t saddr, uint16_t sport, - uint32_t daddr, uint16_t dport, - const void *data, size_t len) -{ - struct iovec iov[3]; - - memset(ip, 0, sizeof(*ip)); - memset(udp, 0, sizeof(*udp)); - - ip->version = IPVERSION; - ip->ihl = sizeof(struct iphdr) / 4; - ip->tot_len = L_CPU_TO_BE16(len + sizeof(*ip) + sizeof(*udp)); - - ip->protocol = IPPROTO_UDP; - ip->saddr = L_CPU_TO_BE32(saddr); - ip->daddr = L_CPU_TO_BE32(daddr); - - udp->source = L_CPU_TO_BE16(sport); - udp->dest = L_CPU_TO_BE16(dport); - - udp->len = L_CPU_TO_BE16(len + sizeof(*udp)); - - ip->check = udp->len; - - iov[0].iov_base = &ip->ttl; - iov[0].iov_len = sizeof(*ip) - 8; - iov[1].iov_base = udp; - iov[1].iov_len = sizeof(*udp); - iov[2].iov_base = (void *) data; - iov[2].iov_len = len; - udp->check = _dhcp_checksumv(iov, 3); - - ip->ttl = IPDEFTTL; - ip->check = 0; - - iov[0].iov_base = ip; - iov[0].iov_len = sizeof(*ip); - ip->check = _dhcp_checksumv(iov, 1); -} - -static int _dhcp_default_transport_broadcast(struct dhcp_transport *s, - uint32_t saddr, uint16_t sport, - uint32_t daddr, uint16_t dport, - const void *data, size_t len) -{ - struct dhcp_default_transport *transport = - l_container_of(s, struct dhcp_default_transport, super); - struct sockaddr_ll addr; - struct iovec iov[3]; - struct iphdr ip; - struct udphdr udp; - struct msghdr msg; - - dhcp_set_ip_udp_headers(&ip, &udp, - saddr, sport, daddr, dport, data, len); - iov[0].iov_base = &ip; - iov[0].iov_len = sizeof(ip); - iov[1].iov_base = &udp; - iov[1].iov_len = sizeof(udp); - iov[2].iov_base = (void *) data; - iov[2].iov_len = len; - - memset(&addr, 0, sizeof(addr)); - addr.sll_family = AF_PACKET; - addr.sll_protocol = htons(ETH_P_IP); - addr.sll_ifindex = s->ifindex; - addr.sll_halen = ETH_ALEN; - memset(addr.sll_addr, 0xff, ETH_ALEN); - - memset(&msg, 0, sizeof(msg)); - msg.msg_name = &addr; - msg.msg_namelen = sizeof(addr); - msg.msg_iov = iov; - msg.msg_iovlen = 3; - - if (sendmsg(l_io_get_fd(transport->io), &msg, 0) < 0) - goto error; - - errno = 0; - -error: - return -errno; -} - -static int _dhcp_default_transport_send(struct dhcp_transport *s, - const struct sockaddr_in *dest, - const void *data, size_t len) -{ - struct dhcp_default_transport *transport = - l_container_of(s, struct dhcp_default_transport, super); - int err; - - err = sendto(transport->udp_fd, data, len, 0, - (const struct sockaddr *) dest, sizeof(*dest)); - - if (err < 0) - return -errno; - - return 0; -} - -static int kernel_udp_socket_open(const char *ifname, - uint32_t addr, uint16_t port) -{ - int s; - int err; - int one = 1; - struct sockaddr_in saddr; - struct sock_filter filter[] = { - /* ignore */ - BPF_STMT(BPF_RET + BPF_K, 0), - }; - struct sock_fprog fprog = { - .len = L_ARRAY_SIZE(filter), - .filter = filter - }; - - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) - return -errno; - - if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, - &fprog, sizeof(fprog)) < 0) - goto error; - - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) - goto error; - - if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, - ifname, strlen(ifname) + 1) < 0) - goto error; - - /* - * Just in case we need to bind the address prior to it being - * configured via rtnl - */ - if (setsockopt(s, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0) - goto error; - - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_port = L_CPU_TO_BE16(port); - saddr.sin_addr.s_addr = addr; - - err = bind(s, (struct sockaddr *) &saddr, sizeof(struct sockaddr_in)); - if (err < 0) - goto error; - - return s; - -error: - L_TFR(close(s)); - return -errno; -} - -static int _dhcp_default_transport_bind(struct dhcp_transport *s, - uint32_t saddr) -{ - struct dhcp_default_transport *transport = - l_container_of(s, struct dhcp_default_transport, super); - int fd; - - if (!transport->io) - return -EIO; - - fd = kernel_udp_socket_open(transport->ifname, saddr, transport->port); - if (fd < 0) - return fd; - - transport->udp_fd = fd; - - return 0; -} - -static int kernel_raw_socket_open(uint32_t ifindex, uint16_t port, uint32_t xid) -{ - int s; - struct sockaddr_ll addr; - struct sock_filter filter[] = { - /* A <- packet length */ - BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), - /* A >= sizeof(dhcp_packet) ? */ - BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, - sizeof(struct dhcp_packet), 1, 0), - /* ignore */ - BPF_STMT(BPF_RET + BPF_K, 0), - /* A <- IP version + Header length */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 0), - /* A <- A & 0xf0 (Mask off version */ - BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0xf0), - /* A == IPVERSION (shifted left 4) ? */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPVERSION << 4, 1, 0), - /* ignore */ - BPF_STMT(BPF_RET + BPF_K, 0), - /* A <- IP version + Header length */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 0), - /* A <- A & 0x0f (Mask off IP Header Length */ - BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x0f), - /* A == 5 ? */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 5, 1, 0), - /* ignore */ - BPF_STMT(BPF_RET + BPF_K, 0), - /* A <- IP protocol */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, - offsetof(struct dhcp_packet, ip.protocol)), - /* IP protocol == UDP ? */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0), - /* ignore */ - BPF_STMT(BPF_RET + BPF_K, 0), - /* A <- Flags + Fragment offset */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, - offsetof(struct dhcp_packet, ip.frag_off)), - /* A <- A & 0x3fff (fragment flag + fragment offset) */ - BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x3fff), - /* A == 0 ? */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), - /* ignore */ - BPF_STMT(BPF_RET + BPF_K, 0), - /* A <- UDP destination port */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, - offsetof(struct dhcp_packet, udp.dest)), - /* UDP destination port == DHCP client port ? */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, port, 1, 0), - /* ignore */ - BPF_STMT(BPF_RET + BPF_K, 0), - /* A <- DHCP op */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, - offsetof(struct dhcp_packet, dhcp.op)), - /* op == BOOTREPLY ? */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, - DHCP_OP_CODE_BOOTREPLY, 1, 0), - /* ignore */ - BPF_STMT(BPF_RET + BPF_K, 0), - /* A <- DHCP header type */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, - offsetof(struct dhcp_packet, dhcp.htype)), - /* header type == arp_type ? */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), - /* ignore */ - BPF_STMT(BPF_RET + BPF_K, 0), - /* A <- client identifier */ - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, - offsetof(struct dhcp_packet, dhcp.xid)), - /* client identifier == xid ? */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0), - /* ignore */ - BPF_STMT(BPF_RET + BPF_K, 0), - /* A <- MAC address length */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, - offsetof(struct dhcp_packet, dhcp.hlen)), - /* address length == dhcp_hlen ? */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 1, 0), - /* ignore */ - BPF_STMT(BPF_RET + BPF_K, 0), - /* A <- DHCP magic cookie */ - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, - offsetof(struct dhcp_packet, dhcp.magic)), - /* cookie == DHCP magic cookie ? */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC, 1, 0), - /* ignore */ - BPF_STMT(BPF_RET + BPF_K, 0), - /* return all */ - BPF_STMT(BPF_RET + BPF_K, 65535), - }; - const struct sock_fprog fprog = { - .len = L_ARRAY_SIZE(filter), - .filter = filter - }; - - s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (s < 0) - return -errno; - - if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, - &fprog, sizeof(fprog)) < 0) - goto error; - - memset(&addr, 0, sizeof(addr)); - addr.sll_family = AF_PACKET; - addr.sll_protocol = htons(ETH_P_IP); - addr.sll_ifindex = ifindex; - addr.sll_halen = ETH_ALEN; - memset(addr.sll_addr, 0xff, ETH_ALEN); - - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) - goto error; - - return s; - -error: - L_TFR(close(s)); - return -errno; -} - -static int _dhcp_default_transport_open(struct dhcp_transport *s, uint32_t xid) -{ - struct dhcp_default_transport *transport = - l_container_of(s, struct dhcp_default_transport, super); - int fd; - - if (transport->io) - return -EALREADY; - - fd = kernel_raw_socket_open(s->ifindex, transport->port, xid); - if (fd < 0) - return fd; - - transport->io = l_io_new(fd); - l_io_set_close_on_destroy(transport->io, true); - l_io_set_read_handler(transport->io, - _dhcp_default_transport_read_handler, - transport, NULL); - - return 0; -} - -static void _dhcp_default_transport_close(struct dhcp_transport *s) -{ - struct dhcp_default_transport *transport = - l_container_of(s, struct dhcp_default_transport, super); - - l_io_destroy(transport->io); - transport->io = NULL; - - if (transport->udp_fd >= 0) { - L_TFR(close(transport->udp_fd)); - transport->udp_fd = -1; - } -} - -struct dhcp_transport *_dhcp_default_transport_new(uint32_t ifindex, - const char *ifname, - uint16_t port) -{ - struct dhcp_default_transport *transport; - transport = l_new(struct dhcp_default_transport, 1); - - transport->super.open = _dhcp_default_transport_open; - transport->super.bind = _dhcp_default_transport_bind; - transport->super.close = _dhcp_default_transport_close; - transport->super.send = _dhcp_default_transport_send; - transport->super.broadcast = _dhcp_default_transport_broadcast; - - transport->super.ifindex = ifindex; - l_strlcpy(transport->ifname, ifname, IFNAMSIZ); - transport->port = port; - - return &transport->super; -} - -void _dhcp_transport_free(struct dhcp_transport *transport) -{ - if (!transport) - return; - - if (transport->close) - transport->close(transport); - - l_free(transport); -} - -void _dhcp_transport_set_rx_callback(struct dhcp_transport *transport, - dhcp_transport_rx_cb_t rx_cb, - void *userdata) -{ - if (!transport) - return; - - transport->rx_cb = rx_cb; - transport->rx_data = userdata; -} diff --git a/ell/dhcp.c b/ell/dhcp.c deleted file mode 100644 index 9ee5ced..0000000 --- a/ell/dhcp.c +++ /dev/null @@ -1,1277 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "private.h" -#include "random.h" -#include "time.h" -#include "net.h" -#include "timeout.h" -#include "dhcp.h" -#include "dhcp-private.h" - -#define CLIENT_DEBUG(fmt, args...) \ - l_util_debug(client->debug_handler, client->debug_data, \ - "%s:%i " fmt, __func__, __LINE__, ## args) -#define CLIENT_ENTER_STATE(s) \ - l_util_debug(client->debug_handler, client->debug_data, \ - "%s:%i Entering state: " #s, \ - __func__, __LINE__); \ - client->state = (s) - -#define BITS_PER_LONG (sizeof(unsigned long) * 8) - -#define DHCP_OPTION_PAD 0 /* RFC 2132, Section 3.1 */ -#define DHCP_OPTION_END 255 /* RFC 2132, Section 3.2 */ - -/* RFC 2132, Section 9.3. Option Overload */ -#define DHCP_OPTION_OVERLOAD 52 -enum dhcp_option_overload { - DHCP_OVERLOAD_FILE = 1, - DHCP_OVERLOAD_SNAME = 2, - DHCP_OVERLOAD_BOTH = 3, -}; - -/* RFC 2132, Section 9.6. DHCP Message Type */ -#define DHCP_OPTION_MESSAGE_TYPE 53 -enum dhcp_message_type { - DHCP_MESSAGE_TYPE_DISCOVER = 1, - DHCP_MESSAGE_TYPE_OFFER = 2, - DHCP_MESSAGE_TYPE_REQUEST = 3, - DHCP_MESSAGE_TYPE_DECLINE = 4, - DHCP_MESSAGE_TYPE_ACK = 5, - DHCP_MESSAGE_TYPE_NAK = 6, - DHCP_MESSAGE_TYPE_RELEASE = 7, - DHCP_MESSAGE_TYPE_INFORM = 8, -}; - -#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* Section 9.8 */ -#define DHCP_OPTION_MAXIMUM_MESSAGE_SIZE 57 /* Section 9.10 */ -#define DHCP_OPTION_CLIENT_IDENTIFIER 61 /* Section 9.14 */ - -enum dhcp_state { - DHCP_STATE_INIT, - DHCP_STATE_SELECTING, - DHCP_STATE_INIT_REBOOT, - DHCP_STATE_REBOOTING, - DHCP_STATE_REQUESTING, - DHCP_STATE_BOUND, - DHCP_STATE_RENEWING, - DHCP_STATE_REBINDING, -}; - -const char *_dhcp_message_type_to_string(uint8_t type) -{ - switch(type) { - case DHCP_MESSAGE_TYPE_DISCOVER: - return "DHCPDISCOVER"; - case DHCP_MESSAGE_TYPE_OFFER: - return "DHCPOFFER"; - case DHCP_MESSAGE_TYPE_REQUEST: - return "DHCPREQUEST"; - case DHCP_MESSAGE_TYPE_DECLINE: - return "DHCPDECLINE"; - case DHCP_MESSAGE_TYPE_ACK: - return "DHCPACK"; - case DHCP_MESSAGE_TYPE_NAK: - return "DHCPNAK"; - case DHCP_MESSAGE_TYPE_RELEASE: - return "DHCPRELEASE"; - default: - return "unknown"; - } -} - -const char *_dhcp_option_to_string(uint8_t option) -{ - switch (option) { - case DHCP_OPTION_PAD: - return "Pad"; - case L_DHCP_OPTION_SUBNET_MASK: - return "Subnet Mask"; - case L_DHCP_OPTION_ROUTER: - return "Router"; - case L_DHCP_OPTION_DOMAIN_NAME_SERVER: - return "Domain Name Server"; - case L_DHCP_OPTION_HOST_NAME: - return "Host Name"; - case L_DHCP_OPTION_DOMAIN_NAME: - return "Domain Name"; - case L_DHCP_OPTION_BROADCAST_ADDRESS: - return "Broadcast Address"; - case L_DHCP_OPTION_NTP_SERVERS: - return "NTP Servers"; - case L_DHCP_OPTION_REQUESTED_IP_ADDRESS: - return "IP Address"; - case L_DHCP_OPTION_IP_ADDRESS_LEASE_TIME: - return "IP Address Lease Time"; - case DHCP_OPTION_OVERLOAD: - return "Overload"; - case DHCP_OPTION_MESSAGE_TYPE: - return "DHCP Message Type"; - case L_DHCP_OPTION_SERVER_IDENTIFIER: - return "Server Identifier"; - case DHCP_OPTION_PARAMETER_REQUEST_LIST: - return "Parameter Request List"; - case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE: - return "Maximum Message Size"; - case L_DHCP_OPTION_RENEWAL_T1_TIME: - return "Renewal Time"; - case L_DHCP_OPTION_REBINDING_T2_TIME: - return "Rebinding Time"; - case DHCP_OPTION_CLIENT_IDENTIFIER: - return "Client Identifier"; - case DHCP_OPTION_END: - return "End"; - default: - return "unknown"; - }; -} - -bool _dhcp_message_iter_init(struct dhcp_message_iter *iter, - const struct dhcp_message *message, size_t len) -{ - if (!message) - return false; - - if (len < sizeof(struct dhcp_message)) - return false; - - if (L_BE32_TO_CPU(message->magic) != DHCP_MAGIC) - return false; - - memset(iter, 0, sizeof(*iter)); - iter->message = message; - iter->message_len = len; - iter->max = len - sizeof(struct dhcp_message); - iter->options = message->options; - iter->can_overload = true; - - return true; -} - -static bool next_option(struct dhcp_message_iter *iter, - uint8_t *t, uint8_t *l, const void **v) -{ - uint8_t type; - uint8_t len; - - while (iter->pos < iter->max) { - type = iter->options[iter->pos]; - - switch (type) { - case DHCP_OPTION_PAD: - iter->pos += 1; - continue; - case DHCP_OPTION_END: - return false; - default: - break; - } - - if (iter->pos + 2 >= iter->max) - return false; - - len = iter->options[iter->pos + 1]; - - if (iter->pos + 2 + len > iter->max) - return false; - - *t = type; - *l = len; - *v = &iter->options[iter->pos + 2]; - - iter->pos += 2 + len; - return true; - } - - return false; -} - -bool _dhcp_message_iter_next(struct dhcp_message_iter *iter, uint8_t *type, - uint8_t *len, const void **data) -{ - bool r; - uint8_t t, l; - const void *v; - - do { - r = next_option(iter, &t, &l, &v); - if (!r) { - iter->can_overload = false; - - if (iter->overload_file) { - iter->options = iter->message->file; - iter->pos = 0; - iter->max = sizeof(iter->message->file); - iter->overload_file = false; - continue; - } - - if (iter->overload_sname) { - iter->options = iter->message->sname; - iter->pos = 0; - iter->max = sizeof(iter->message->sname); - iter->overload_sname = false; - continue; - } - - return r; - } - - switch (t) { - case DHCP_OPTION_OVERLOAD: - if (l != 1) - continue; - - if (!iter->can_overload) - continue; - - if (l_get_u8(v) & DHCP_OVERLOAD_FILE) - iter->overload_file = true; - - if (l_get_u8(v) & DHCP_OVERLOAD_SNAME) - iter->overload_sname = true; - - continue; - default: - if (type) - *type = t; - - if (len) - *len = l; - - if (data) - *data = v; - return r; - } - } while (true); - - return false; -} - -int _dhcp_option_append(uint8_t **buf, size_t *buflen, uint8_t code, - size_t optlen, const void *optval) -{ - if (!buf || !buflen) - return -EINVAL; - - switch (code) { - - case DHCP_OPTION_PAD: - case DHCP_OPTION_END: - if (*buflen < 1) - return -ENOBUFS; - - (*buf)[0] = code; - *buf += 1; - *buflen -= 1; - break; - - default: - if (*buflen < optlen + 2) - return -ENOBUFS; - - if (!optval) - return -EINVAL; - - (*buf)[0] = code; - (*buf)[1] = optlen; - memcpy(&(*buf)[2], optval, optlen); - - *buf += optlen + 2; - *buflen -= (optlen + 2); - - break; - } - - return 0; -} - -static int dhcp_append_prl(const unsigned long *reqopts, - uint8_t **buf, size_t *buflen) -{ - uint8_t optlen = 0; - unsigned int i; - unsigned int j; - - if (!buf || !buflen) - return -EINVAL; - - for (i = 0; i < 256 / BITS_PER_LONG; i++) - optlen += __builtin_popcountl(reqopts[i]); - - /* - * This function assumes that there's enough space to put the PRL - * into the buffer without resorting to file or sname overloading - */ - if (*buflen < optlen + 2U) - return -ENOBUFS; - - i = 0; - (*buf)[i++] = DHCP_OPTION_PARAMETER_REQUEST_LIST; - (*buf)[i++] = optlen; - - for (j = 0; j < 256; j++) { - if (reqopts[j / BITS_PER_LONG] & 1UL << (j % BITS_PER_LONG)) - (*buf)[i++] = j; - } - - *buf += optlen + 2; - *buflen -= (optlen + 2); - - return 0; -} - -static int dhcp_message_init(struct dhcp_message *message, - enum dhcp_op_code op, - uint8_t type, uint32_t xid, - uint8_t **opt, size_t *optlen) -{ - int err; - - message->op = op; - message->xid = L_CPU_TO_BE32(xid); - message->magic = L_CPU_TO_BE32(DHCP_MAGIC); - *opt = (uint8_t *)(message + 1); - - err = _dhcp_option_append(opt, optlen, - DHCP_OPTION_MESSAGE_TYPE, 1, &type); - if (err < 0) - return err; - - return 0; -} - -static void dhcp_message_set_address_type(struct dhcp_message *message, - uint8_t addr_type, - uint8_t addr_len) -{ - message->htype = addr_type; - - switch (addr_type) { - case ARPHRD_ETHER: - message->hlen = addr_len; - break; - default: - message->hlen = 0; - } -} - -static inline int dhcp_message_optimize(struct dhcp_message *message, - const uint8_t *end) -{ - /* - * Don't bother sending a full sized dhcp_message as it is most likely - * mostly zeros. Instead truncate it at DHCP_OPTION_END and align to - * the nearest 4 byte boundary. Many implementations expect a packet - * of a certain size or it is filtered, so we cap the length in - * accordance to RFC 1542: - * "The IP Total Length and UDP Length must be large enough to contain - * the minimal BOOTP header of 300 octets" - */ - size_t len = align_len(end - (uint8_t *) message, 4); - if (len < 300) - len = 300; - - return len; -} - -#define DHCP_MIN_OPTIONS_SIZE 312 - -struct l_dhcp_client { - enum dhcp_state state; - unsigned long request_options[256 / BITS_PER_LONG]; - uint32_t ifindex; - char *ifname; - uint8_t addr[6]; - uint8_t addr_len; - uint8_t addr_type; - char *hostname; - uint32_t xid; - struct dhcp_transport *transport; - uint64_t start_t; - struct l_timeout *timeout_resend; - struct l_timeout *timeout_lease; - struct l_dhcp_lease *lease; - uint8_t attempt; - l_dhcp_client_event_cb_t event_handler; - void *event_data; - l_dhcp_destroy_cb_t event_destroy; - l_dhcp_debug_cb_t debug_handler; - l_dhcp_destroy_cb_t debug_destroy; - void *debug_data; - bool have_addr : 1; - bool override_xid : 1; -}; - -static inline void dhcp_enable_option(struct l_dhcp_client *client, - uint8_t option) -{ - client->request_options[option / BITS_PER_LONG] |= - 1UL << (option % BITS_PER_LONG); -} - -static uint16_t dhcp_attempt_secs(uint64_t start) -{ - uint64_t now = l_time_now(); - uint64_t elapsed = l_time_to_secs(now - start); - - if (elapsed == 0) - return 1; - - if (elapsed > UINT16_MAX) - return UINT16_MAX; - - return elapsed; -} - -/* - * Takes a time in seconds and produces a fuzzed value that can be directly - * used by l_timeout_modify_ms - */ -static uint64_t dhcp_fuzz_secs(uint32_t secs) -{ - uint64_t ms = secs * 1000ULL; - uint32_t r = l_getrandom_uint32(); - - /* - * RFC2132, Section 4.1: - * DHCP clients are responsible for all message retransmission. The - * client MUST adopt a retransmission strategy that incorporates a - * randomized exponential backoff algorithm to determine the delay - * between retransmissions. - * - * and later in the same paragraph: - * For example, in a 10Mb/sec Ethernet internetwork, the delay before - * the first retransmission SHOULD be 4 seconds randomized by the - * value of a uniform random number chosen from the range -1 to +1. - * Clients with clocks that provide resolution granularity of less than - * one second may choose a non-integer randomization value. - */ - if (r & 0x80000000) - ms += r & 0x3ff; - else - ms -= r & 0x3ff; - - return ms; -} - -/* - * Takes a time in milliseconds and produces a fuzzed value that can be directly - * used by l_timeout_modify_ms. The fluctuation of the random noise added is - * from -63 to 63 milliseconds. - */ -static uint64_t dhcp_fuzz_msecs(uint64_t ms) -{ - uint32_t r = l_getrandom_uint32(); - - if (r & 0x80000000) - ms += r & 0x3f; - else - ms -= r & 0x3f; - - return ms; -} - -static uint32_t dhcp_rebind_renew_retry_time(uint64_t start_t, uint32_t expiry) -{ - uint64_t now = l_time_now(); - uint32_t relative_now; - uint32_t retry_time; - - /* - * RFC 2131, Section 4.4.5: - * " In both RENEWING and REBINDING states, if the client receives no - * response to its DHCPREQUEST message, the client SHOULD wait one-half - * of the remaining time until T2 (in RENEWING state) and one-half of - * the remaining lease time (in REBINDING state), down to a minimum of - * 60 seconds, before retransmitting the DHCPREQUEST message. - */ - relative_now = l_time_to_secs(now - start_t); - retry_time = (expiry - relative_now) / 2; - - if (retry_time < 60) - retry_time = 60; - - return retry_time; -} - -static int client_message_init(struct l_dhcp_client *client, - struct dhcp_message *message, - uint8_t type, - uint8_t **opt, size_t *optlen) -{ - int err; - uint16_t max_size; - - err = dhcp_message_init(message, DHCP_OP_CODE_BOOTREQUEST, - type, client->xid, opt, optlen); - if (err < 0) - return err; - - dhcp_message_set_address_type(message, client->addr_type, - client->addr_len); - /* - * RFC2132 section 4.1.1: - * The client MUST include its hardware address in the ’chaddr’ field, - * if necessary for delivery of DHCP reply messages. Non-Ethernet - * interfaces will leave 'chaddr' empty and use the client identifier - * instead - */ - if (client->addr_type == ARPHRD_ETHER) - memcpy(message->chaddr, &client->addr, client->addr_len); - - /* - * Althrough RFC 2131 says that secs should be initialized to 0, - * some servers refuse to give us a lease unless we set this to a - * non-zero value - */ - message->secs = L_CPU_TO_BE16(dhcp_attempt_secs(client->start_t)); - - err = dhcp_append_prl(client->request_options, opt, optlen); - if (err < 0) - return err; - - /* - * Set the maximum DHCP message size to the minimum legal value. This - * helps some buggy DHCP servers to not send bigger packets - */ - max_size = L_CPU_TO_BE16(576); - err = _dhcp_option_append(opt, optlen, - DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, - 2, &max_size); - if (err < 0) - return err; - - return 0; -} - -static void dhcp_client_event_notify(struct l_dhcp_client *client, - enum l_dhcp_client_event event) -{ - if (client->event_handler) - client->event_handler(client, event, client->event_data); -} - -static int dhcp_client_send_discover(struct l_dhcp_client *client) -{ - uint8_t *opt; - size_t optlen = DHCP_MIN_OPTIONS_SIZE; - size_t len = sizeof(struct dhcp_message) + optlen; - L_AUTO_FREE_VAR(struct dhcp_message *, discover); - int err; - - CLIENT_DEBUG(""); - - discover = (struct dhcp_message *) l_new(uint8_t, len); - - err = client_message_init(client, discover, - DHCP_MESSAGE_TYPE_DISCOVER, - &opt, &optlen); - if (err < 0) - return err; - - if (client->hostname) { - err = _dhcp_option_append(&opt, &optlen, - L_DHCP_OPTION_HOST_NAME, - strlen(client->hostname), - client->hostname); - if (err < 0) - return err; - } - - err = _dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL); - if (err < 0) - return err; - - len = dhcp_message_optimize(discover, opt); - - return client->transport->broadcast(client->transport, - INADDR_ANY, DHCP_PORT_CLIENT, - INADDR_BROADCAST, DHCP_PORT_SERVER, - discover, len); -} - -static int dhcp_client_send_request(struct l_dhcp_client *client) -{ - uint8_t *opt; - size_t optlen = DHCP_MIN_OPTIONS_SIZE; - size_t len = sizeof(struct dhcp_message) + optlen; - L_AUTO_FREE_VAR(struct dhcp_message *, request); - int err; - - CLIENT_DEBUG(""); - - request = (struct dhcp_message *) l_new(uint8_t, len); - - err = client_message_init(client, request, - DHCP_MESSAGE_TYPE_REQUEST, - &opt, &optlen); - if (err < 0) - return err; - - switch (client->state) { - case DHCP_STATE_REQUESTING: - /* - * RFC 2131, Section 4.3.2: - * "If the DHCPREQUEST message contains a 'server identifier' - * option, the message is in response to a DHCPOFFER message." - * - * and - * - * "DHCPREQUEST generated during SELECTING state: - * Client inserts the address of the selected server in - * 'server identifier', 'ciaddr' MUST be zero, 'requested IP - * address' MUST be filled in with the yiaddr value from the - * chosen DHCPOFFER." - * - * NOTE: 'SELECTING' is meant to be 'REQUESTING' in the RFC - */ - err = _dhcp_option_append(&opt, &optlen, - L_DHCP_OPTION_SERVER_IDENTIFIER, - 4, &client->lease->server_address); - if (err < 0) - return err; - - err = _dhcp_option_append(&opt, &optlen, - L_DHCP_OPTION_REQUESTED_IP_ADDRESS, - 4, &client->lease->address); - if (err < 0) - return err; - break; - case DHCP_STATE_RENEWING: - case DHCP_STATE_REBINDING: - request->ciaddr = client->lease->address; - break; - - case DHCP_STATE_INIT: - case DHCP_STATE_SELECTING: - case DHCP_STATE_INIT_REBOOT: - case DHCP_STATE_REBOOTING: - case DHCP_STATE_BOUND: - return -EINVAL; - } - - if (client->hostname) { - err = _dhcp_option_append(&opt, &optlen, - L_DHCP_OPTION_HOST_NAME, - strlen(client->hostname), - client->hostname); - if (err < 0) - return err; - } - - err = _dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL); - if (err < 0) - return err; - - len = dhcp_message_optimize(request, opt); - - /* - * RFC2131, Section 4.1: - * "DHCP clients MUST use the IP address provided in the - * 'server identifier' option for any unicast requests to the DHCP - * server. - */ - if (client->state == DHCP_STATE_RENEWING) { - struct sockaddr_in si; - memset(&si, 0, sizeof(si)); - si.sin_family = AF_INET; - si.sin_port = L_CPU_TO_BE16(DHCP_PORT_SERVER); - si.sin_addr.s_addr = client->lease->server_address; - return client->transport->send(client->transport, - &si, request, len); - } - - return client->transport->broadcast(client->transport, - INADDR_ANY, DHCP_PORT_CLIENT, - INADDR_BROADCAST, DHCP_PORT_SERVER, - request, len); -} - -static void dhcp_client_timeout_resend(struct l_timeout *timeout, - void *user_data) -{ - struct l_dhcp_client *client = user_data; - unsigned int next_timeout = 0; - - CLIENT_DEBUG(""); - - switch (client->state) { - case DHCP_STATE_SELECTING: - if (dhcp_client_send_discover(client) < 0) - goto error; - break; - case DHCP_STATE_RENEWING: - case DHCP_STATE_REQUESTING: - case DHCP_STATE_REBINDING: - if (dhcp_client_send_request(client) < 0) - goto error; - break; - case DHCP_STATE_INIT: - case DHCP_STATE_INIT_REBOOT: - case DHCP_STATE_REBOOTING: - case DHCP_STATE_BOUND: - break; - } - - switch (client->state) { - case DHCP_STATE_RENEWING: - next_timeout = dhcp_rebind_renew_retry_time(client->start_t, - client->lease->t2); - break; - case DHCP_STATE_REBINDING: - next_timeout = dhcp_rebind_renew_retry_time(client->start_t, - client->lease->lifetime); - break; - case DHCP_STATE_REQUESTING: - case DHCP_STATE_SELECTING: - /* - * RFC 2131 Section 4.1: - * "The retransmission delay SHOULD be doubled with subsequent - * retransmissions up to a maximum of 64 seconds. - */ - client->attempt += 1; - next_timeout = minsize(2 << client->attempt, 64); - break; - case DHCP_STATE_INIT: - case DHCP_STATE_INIT_REBOOT: - case DHCP_STATE_REBOOTING: - case DHCP_STATE_BOUND: - break; - }; - - if (next_timeout) - l_timeout_modify_ms(timeout, dhcp_fuzz_secs(next_timeout)); - - return; - -error: - l_dhcp_client_stop(client); -} - -static void dhcp_client_t2_expired(struct l_timeout *timeout, void *user_data) -{ - struct l_dhcp_client *client = user_data; - - CLIENT_DEBUG(""); - - /* - * If we got here, then resend_timeout is active, with a timeout - * set originally for ~60 seconds. So we simply set the new state - * and wait for the timer to fire - */ - CLIENT_ENTER_STATE(DHCP_STATE_REBINDING); - - /* TODO: Start timer for the expiration time */ -} - -static void dhcp_client_t1_expired(struct l_timeout *timeout, void *user_data) -{ - struct l_dhcp_client *client = user_data; - uint32_t next_timeout; - - CLIENT_DEBUG(""); - - CLIENT_ENTER_STATE(DHCP_STATE_RENEWING); - client->attempt = 1; - - if (dhcp_client_send_request(client) < 0) - goto error; - - next_timeout = client->lease->t2 - client->lease->t1; - l_timeout_modify_ms(client->timeout_lease, - dhcp_fuzz_secs(next_timeout)); - l_timeout_set_callback(client->timeout_lease, dhcp_client_t2_expired, - client, NULL); - - next_timeout = dhcp_rebind_renew_retry_time(client->start_t, - client->lease->t2); - client->timeout_resend = - l_timeout_create_ms(dhcp_fuzz_secs(next_timeout), - dhcp_client_timeout_resend, - client, NULL); - return; - -error: - l_dhcp_client_stop(client); -} - -static int dhcp_client_receive_ack(struct l_dhcp_client *client, - const struct dhcp_message *ack, - size_t len) -{ - struct dhcp_message_iter iter; - struct l_dhcp_lease *lease; - int r; - - CLIENT_DEBUG(""); - - if (ack->yiaddr == 0) - return -ENOMSG; - - if (!_dhcp_message_iter_init(&iter, ack, len)) - return -EINVAL; - - lease = _dhcp_lease_parse_options(&iter); - if (!lease) - return -ENOMSG; - - lease->address = ack->yiaddr; - - r = L_DHCP_CLIENT_EVENT_LEASE_RENEWED; - - if (client->lease) { - if (client->lease->subnet_mask != lease->subnet_mask || - client->lease->address != lease->address || - client->lease->router != lease->router) - r = L_DHCP_CLIENT_EVENT_IP_CHANGED; - - _dhcp_lease_free(client->lease); - } - - client->lease = lease; - - /* In case this is an initial request, override to LEASE_OBTAINED */ - if (client->state == DHCP_STATE_REQUESTING || - client->state == DHCP_STATE_REBOOTING) - r = L_DHCP_CLIENT_EVENT_LEASE_OBTAINED; - - return r; -} - -static int dhcp_client_receive_offer(struct l_dhcp_client *client, - const struct dhcp_message *offer, - size_t len) -{ - struct dhcp_message_iter iter; - - CLIENT_DEBUG(""); - - if (offer->yiaddr == 0) - return -ENOMSG; - - if (!_dhcp_message_iter_init(&iter, offer, len)) - return -EINVAL; - - client->lease = _dhcp_lease_parse_options(&iter); - if (!client->lease) - return -ENOMSG; - - client->lease->address = offer->yiaddr; - - return 0; -} - -static void dhcp_client_rx_message(const void *data, size_t len, void *userdata) -{ - struct l_dhcp_client *client = userdata; - const struct dhcp_message *message = data; - struct dhcp_message_iter iter; - uint8_t msg_type = 0; - uint8_t t, l; - const void *v; - int r; - - CLIENT_DEBUG(""); - - if (len < sizeof(struct dhcp_message)) - return; - - if (message->op != DHCP_OP_CODE_BOOTREPLY) - return; - - if (L_BE32_TO_CPU(message->xid) != client->xid) - return; - - if (memcmp(message->chaddr, client->addr, client->addr_len)) - return; - - if (!_dhcp_message_iter_init(&iter, message, len)) - return; - - while (_dhcp_message_iter_next(&iter, &t, &l, &v) && !msg_type) { - switch (t) { - case DHCP_OPTION_MESSAGE_TYPE: - if (l == 1) - msg_type = l_get_u8(v); - break; - } - } - - switch (client->state) { - case DHCP_STATE_INIT: - return; - case DHCP_STATE_SELECTING: - if (msg_type != DHCP_MESSAGE_TYPE_OFFER) - return; - - if (dhcp_client_receive_offer(client, message, len) < 0) - return; - - CLIENT_ENTER_STATE(DHCP_STATE_REQUESTING); - client->attempt = 1; - - if (dhcp_client_send_request(client) < 0) { - l_dhcp_client_stop(client); - - return; - } - - l_timeout_modify_ms(client->timeout_resend, dhcp_fuzz_secs(4)); - break; - case DHCP_STATE_REQUESTING: - case DHCP_STATE_RENEWING: - case DHCP_STATE_REBINDING: - if (msg_type == DHCP_MESSAGE_TYPE_NAK) { - l_dhcp_client_stop(client); - - dhcp_client_event_notify(client, - L_DHCP_CLIENT_EVENT_NO_LEASE); - return; - } - - if (msg_type != DHCP_MESSAGE_TYPE_ACK) - return; - - r = dhcp_client_receive_ack(client, message, len); - if (r < 0) - return; - - CLIENT_ENTER_STATE(DHCP_STATE_BOUND); - l_timeout_remove(client->timeout_resend); - client->timeout_resend = NULL; - - if (client->transport->bind) - client->transport->bind(client->transport, - client->lease->address); - - dhcp_client_event_notify(client, r); - - /* - * Start T1, once it expires we will start the T2 timer. If - * we renew the lease, we will end up back here. - * - * RFC2131, Section 4.4.5 states: - * "Times T1 and T2 SHOULD be chosen with some random "fuzz" - * around a fixed value, to avoid synchronization of client - * reacquisition." - */ - l_timeout_remove(client->timeout_lease); - client->timeout_lease = - l_timeout_create_ms(dhcp_fuzz_secs(client->lease->t1), - dhcp_client_t1_expired, - client, NULL); - - break; - case DHCP_STATE_INIT_REBOOT: - case DHCP_STATE_REBOOTING: - case DHCP_STATE_BOUND: - break; - } -} - -LIB_EXPORT struct l_dhcp_client *l_dhcp_client_new(uint32_t ifindex) -{ - struct l_dhcp_client *client; - - client = l_new(struct l_dhcp_client, 1); - - client->state = DHCP_STATE_INIT; - client->ifindex = ifindex; - - /* Enable these options by default */ - dhcp_enable_option(client, L_DHCP_OPTION_SUBNET_MASK); - dhcp_enable_option(client, L_DHCP_OPTION_ROUTER); - dhcp_enable_option(client, L_DHCP_OPTION_HOST_NAME); - dhcp_enable_option(client, L_DHCP_OPTION_DOMAIN_NAME); - dhcp_enable_option(client, L_DHCP_OPTION_DOMAIN_NAME_SERVER); - dhcp_enable_option(client, L_DHCP_OPTION_NTP_SERVERS); - - return client; -} - -LIB_EXPORT void l_dhcp_client_destroy(struct l_dhcp_client *client) -{ - if (unlikely(!client)) - return; - - l_dhcp_client_stop(client); - - if (client->event_destroy) - client->event_destroy(client->event_data); - - _dhcp_transport_free(client->transport); - l_free(client->ifname); - l_free(client->hostname); - - l_free(client); -} - -LIB_EXPORT bool l_dhcp_client_add_request_option(struct l_dhcp_client *client, - uint8_t option) -{ - if (unlikely(!client)) - return false; - - if (unlikely(client->state != DHCP_STATE_INIT)) - return false; - - switch (option) { - case DHCP_OPTION_PAD: - case DHCP_OPTION_END: - case DHCP_OPTION_OVERLOAD: - case DHCP_OPTION_MESSAGE_TYPE: - case DHCP_OPTION_PARAMETER_REQUEST_LIST: - return false; - } - - dhcp_enable_option(client, option); - - return true; -} - -LIB_EXPORT bool l_dhcp_client_set_address(struct l_dhcp_client *client, - uint8_t type, - const uint8_t *addr, - size_t addr_len) -{ - if (unlikely(!client)) - return false; - - switch (type) { - case ARPHRD_ETHER: - if (addr_len != ETH_ALEN) - return false; - break; - default: - return false; - } - - client->addr_len = addr_len; - memcpy(client->addr, addr, addr_len); - client->addr_type = type; - - client->have_addr = true; - - return true; -} - -LIB_EXPORT bool l_dhcp_client_set_interface_name(struct l_dhcp_client *client, - const char *ifname) -{ - if (unlikely(!client)) - return false; - - if (unlikely(client->state != DHCP_STATE_INIT)) - return false; - - l_free(client->ifname); - client->ifname = l_strdup(ifname); - - return true; -} - -LIB_EXPORT bool l_dhcp_client_set_hostname(struct l_dhcp_client *client, - const char *hostname) -{ - if (unlikely(!client)) - return false; - - if (unlikely(client->state != DHCP_STATE_INIT)) - return false; - - if (!hostname) - goto done; - - if (client->hostname && !strcmp(client->hostname, hostname)) - return true; - -done: - l_free(client->hostname); - client->hostname = l_strdup(hostname); - - return true; -} - -bool _dhcp_client_set_transport(struct l_dhcp_client *client, - struct dhcp_transport *transport) -{ - if (unlikely(!client)) - return false; - - if (unlikely(client->state != DHCP_STATE_INIT)) - return false; - - if (client->transport) - _dhcp_transport_free(client->transport); - - client->transport = transport; - return true; -} - -void _dhcp_client_override_xid(struct l_dhcp_client *client, uint32_t xid) -{ - client->override_xid = true; - client->xid = xid; -} - -LIB_EXPORT const struct l_dhcp_lease *l_dhcp_client_get_lease( - const struct l_dhcp_client *client) -{ - if (unlikely(!client)) - return NULL; - - return client->lease; -} - -LIB_EXPORT bool l_dhcp_client_start(struct l_dhcp_client *client) -{ - int err; - - if (unlikely(!client)) - return false; - - if (unlikely(client->state != DHCP_STATE_INIT)) - return false; - - if (!client->have_addr) { - uint8_t mac[6]; - - if (!l_net_get_mac_address(client->ifindex, mac)) - return false; - - l_dhcp_client_set_address(client, ARPHRD_ETHER, mac, 6); - } - - if (!client->ifname) { - client->ifname = l_net_get_name(client->ifindex); - - if (!client->ifname) - return false; - } - - if (!client->transport) { - client->transport = - _dhcp_default_transport_new(client->ifindex, - client->ifname, - DHCP_PORT_CLIENT); - - if (!client->transport) - return false; - } - - if (!client->override_xid) - l_getrandom(&client->xid, sizeof(client->xid)); - - if (client->transport->open) - if (client->transport->open(client->transport, - client->xid) < 0) - return false; - - _dhcp_transport_set_rx_callback(client->transport, - dhcp_client_rx_message, - client); - - client->start_t = l_time_now(); - - err = dhcp_client_send_discover(client); - if (err < 0) - return false; - - client->timeout_resend = l_timeout_create_ms(dhcp_fuzz_msecs(600), - dhcp_client_timeout_resend, - client, NULL); - CLIENT_ENTER_STATE(DHCP_STATE_SELECTING); - client->attempt = 1; - - return true; -} - -LIB_EXPORT bool l_dhcp_client_stop(struct l_dhcp_client *client) -{ - if (unlikely(!client)) - return false; - - l_timeout_remove(client->timeout_resend); - client->timeout_resend = NULL; - - l_timeout_remove(client->timeout_lease); - client->timeout_lease = NULL; - - if (client->transport && client->transport->close) - client->transport->close(client->transport); - - client->start_t = 0; - CLIENT_ENTER_STATE(DHCP_STATE_INIT); - - _dhcp_lease_free(client->lease); - client->lease = NULL; - - return true; -} - -LIB_EXPORT bool l_dhcp_client_set_event_handler(struct l_dhcp_client *client, - l_dhcp_client_event_cb_t handler, - void *userdata, - l_dhcp_destroy_cb_t destroy) -{ - if (unlikely(!client)) - return false; - - if (client->event_destroy) - client->event_destroy(client->event_data); - - client->event_handler = handler; - client->event_data = userdata; - client->event_destroy = destroy; - - return true; -} - -LIB_EXPORT bool l_dhcp_client_set_debug(struct l_dhcp_client *client, - l_dhcp_debug_cb_t function, - void *user_data, - l_dhcp_destroy_cb_t destroy) -{ - if (unlikely(!client)) - return false; - - if (client->debug_destroy) - client->debug_destroy(client->debug_data); - - client->debug_handler = function; - client->debug_destroy = destroy; - client->debug_data = user_data; - - return true; -} diff --git a/ell/dhcp.h b/ell/dhcp.h deleted file mode 100644 index c3a4988..0000000 --- a/ell/dhcp.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_DHCP_H -#define __ELL_DHCP_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -struct l_dhcp_client; -struct l_dhcp_lease; - -/* RFC 2132 */ -enum l_dhcp_option { - L_DHCP_OPTION_SUBNET_MASK = 1, /* Section 3.3 */ - L_DHCP_OPTION_ROUTER = 3, /* Section 3.5 */ - L_DHCP_OPTION_DOMAIN_NAME_SERVER = 6, /* Section 3.8 */ - L_DHCP_OPTION_HOST_NAME = 12, /* Section 3.14 */ - L_DHCP_OPTION_DOMAIN_NAME = 15, /* Section 3.17 */ - L_DHCP_OPTION_BROADCAST_ADDRESS = 28, /* Section 5.3 */ - L_DHCP_OPTION_NTP_SERVERS = 42, /* Section 8.3 */ - L_DHCP_OPTION_REQUESTED_IP_ADDRESS = 50, /* Section 9.1 */ - L_DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51, /* Section 9.2 */ - L_DHCP_OPTION_RENEWAL_T1_TIME = 58, /* Section 9.11 */ - L_DHCP_OPTION_REBINDING_T2_TIME = 59, /* Section 9.12 */ - L_DHCP_OPTION_SERVER_IDENTIFIER = 54, /* Section 9.7 */ -}; - -enum l_dhcp_client_event { - L_DHCP_CLIENT_EVENT_LEASE_OBTAINED = 0, - L_DHCP_CLIENT_EVENT_IP_CHANGED, - L_DHCP_CLIENT_EVENT_LEASE_EXPIRED, - L_DHCP_CLIENT_EVENT_LEASE_RENEWED, - L_DHCP_CLIENT_EVENT_NO_LEASE, -}; - -typedef void (*l_dhcp_client_event_cb_t)(struct l_dhcp_client *client, - enum l_dhcp_client_event event, - void *userdata); -typedef void (*l_dhcp_debug_cb_t)(const char *str, void *user_data); -typedef void (*l_dhcp_destroy_cb_t)(void *userdata); - -struct l_dhcp_client *l_dhcp_client_new(uint32_t ifindex); -bool l_dhcp_client_add_request_option(struct l_dhcp_client *client, - uint8_t option); -void l_dhcp_client_destroy(struct l_dhcp_client *client); - -bool l_dhcp_client_set_address(struct l_dhcp_client *client, uint8_t type, - const uint8_t *addr, size_t addr_len); -bool l_dhcp_client_set_interface_name(struct l_dhcp_client *client, - const char *ifname); -bool l_dhcp_client_set_hostname(struct l_dhcp_client *client, - const char *hostname); - -const struct l_dhcp_lease *l_dhcp_client_get_lease( - const struct l_dhcp_client *client); - -bool l_dhcp_client_start(struct l_dhcp_client *client); -bool l_dhcp_client_stop(struct l_dhcp_client *client); - -bool l_dhcp_client_set_event_handler(struct l_dhcp_client *client, - l_dhcp_client_event_cb_t handler, - void *userdata, - l_dhcp_destroy_cb_t destroy); - -bool l_dhcp_client_set_debug(struct l_dhcp_client *client, - l_dhcp_debug_cb_t function, - void *user_data, l_dhcp_destroy_cb_t destroy); - -char *l_dhcp_lease_get_address(const struct l_dhcp_lease *lease); -char *l_dhcp_lease_get_gateway(const struct l_dhcp_lease *lease); -char *l_dhcp_lease_get_netmask(const struct l_dhcp_lease *lease); -char *l_dhcp_lease_get_broadcast(const struct l_dhcp_lease *lease); -char *l_dhcp_lease_get_server_id(const struct l_dhcp_lease *lease); -char **l_dhcp_lease_get_dns(const struct l_dhcp_lease *lease); - -uint32_t l_dhcp_lease_get_t1(const struct l_dhcp_lease *lease); -uint32_t l_dhcp_lease_get_t2(const struct l_dhcp_lease *lease); -uint32_t l_dhcp_lease_get_lifetime(const struct l_dhcp_lease *lease); -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_DHCP_H */ diff --git a/ell/dir.c b/ell/dir.c deleted file mode 100644 index bdab9ff..0000000 --- a/ell/dir.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2017 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include -#include -#include -#include - -#include "private.h" -#include "queue.h" -#include "io.h" -#include "dir.h" - -struct l_dir_watch { - struct watch_desc *desc; - l_dir_watch_event_func_t function; - void *user_data; - l_dir_watch_destroy_func_t destroy; -}; - -struct watch_desc { - int wd; - char *pathname; - struct l_queue *events; - struct l_queue *callbacks; -}; - -struct watch_event { - char *pathname; - uint32_t mask; -}; - -static struct l_io *inotify_io = NULL; -static struct l_queue *watch_list = NULL; - -static void free_event(void *user_data) -{ - struct watch_event *event = user_data; - - l_free(event->pathname); - l_free(event); -} - -static bool desc_match_wd(const void *a, const void *b) -{ - const struct watch_desc *desc = a; - int wd = L_PTR_TO_INT(b); - - return (desc->wd == wd); -} - -static bool desc_match_pathname(const void *a, const void *b) -{ - const struct watch_desc *desc = a; - const char *pathname = b; - - return !strcmp(desc->pathname, pathname); -} - -static bool event_match_pathname(const void *a, const void *b) -{ - const struct watch_event *event = a; - const char *pathname = b; - - return !strcmp(event->pathname, pathname); -} - -static void handle_callback(struct watch_desc *desc, const char *pathname, - enum l_dir_watch_event event) -{ - const struct l_queue_entry *entry; - - for (entry = l_queue_get_entries(desc->callbacks); entry; - entry = entry->next) { - struct l_dir_watch *watch = entry->data; - - if (watch->function) - watch->function(pathname, event, watch->user_data); - } -} - -static void process_event(struct watch_desc *desc, const char *pathname, - uint32_t mask) -{ - struct watch_event *event; - - if (!pathname) - return; - - if (mask & (IN_ACCESS | IN_MODIFY | IN_OPEN | IN_CREATE)) { - event = l_queue_find(desc->events, event_match_pathname, - pathname); - if (!event) { - /* - * When the event for a given pathname is not yet - * created and it is from type IN_MODIFY, then it - * might have been caused by a truncate() system - * call that does not open() the file. However - * treat this as modified as well. - */ - if (mask & IN_MODIFY) { - handle_callback(desc, pathname, - L_DIR_WATCH_EVENT_MODIFIED); - } else { - event = l_new(struct watch_event, 1); - event->pathname = l_strdup(pathname); - event->mask = mask; - - l_queue_push_tail(desc->events, event); - } - } else { - event->mask |= mask; - } - } else if (mask & (IN_CLOSE_WRITE)) { - event = l_queue_remove_if(desc->events, event_match_pathname, - pathname); - if (event) { - /* - * Creation of a new file is treated differently, - * then modification, but for that the original - * system call needs to be looked at. - */ - if (event->mask & IN_CREATE) - handle_callback(desc, pathname, - L_DIR_WATCH_EVENT_CREATED); - else - handle_callback(desc, pathname, - L_DIR_WATCH_EVENT_MODIFIED); - - free_event(event); - } else { - handle_callback(desc, pathname, - L_DIR_WATCH_EVENT_MODIFIED); - } - } else if (mask & (IN_CLOSE_NOWRITE)) { - event = l_queue_remove_if(desc->events, event_match_pathname, - pathname); - if (event) { - if (event->mask & IN_ACCESS) - handle_callback(desc, pathname, - L_DIR_WATCH_EVENT_ACCESSED); - free_event(event); - } - } else if (mask & (IN_MOVED_FROM | IN_DELETE)) { - handle_callback(desc, pathname, L_DIR_WATCH_EVENT_REMOVED); - } else if (mask & (IN_MOVED_TO)) { - handle_callback(desc, pathname, L_DIR_WATCH_EVENT_CREATED); - } -} - -static bool inotify_read_cb(struct l_io *io, void *user_data) -{ - int fd = l_io_get_fd(io); - uint8_t buf[sizeof(struct inotify_event) + NAME_MAX + 1] - __attribute__ ((aligned(__alignof__(struct inotify_event)))); - const void *ptr = buf; - ssize_t len; - - len = L_TFR(read(fd, buf, sizeof(buf))); - if (len <= 0) - return true; - - while (len > 0) { - const struct inotify_event *event = ptr; - const char *name = event->len ? event->name : NULL; - struct watch_desc *desc; - - desc = l_queue_find(watch_list, desc_match_wd, - L_INT_TO_PTR(event->wd)); - if (desc) - process_event(desc, name, event->mask); - - ptr += sizeof(struct inotify_event) + event->len; - len -= sizeof(struct inotify_event) + event->len; - } - - return true; -} - -static int setup_inotify(void) -{ - struct l_io *io; - int fd; - - if (inotify_io) - goto done; - - fd = inotify_init1(IN_CLOEXEC); - if (fd < 0) - return -1; - - io = l_io_new(fd); - if (!io) { - close(fd); - return -1; - } - - l_io_set_close_on_destroy(io, true); - - if (!l_io_set_read_handler(io, inotify_read_cb, NULL, NULL)) { - l_io_destroy(io); - return -1; - } - - watch_list = l_queue_new(); - inotify_io = io; - -done: - return l_io_get_fd(inotify_io); -} - -static void shutdown_inotify(void) -{ - if (!inotify_io) - return; - - if (l_queue_isempty(watch_list)) { - l_io_destroy(inotify_io); - inotify_io = NULL; - - l_queue_destroy(watch_list, NULL); - watch_list = NULL; - } -} - -LIB_EXPORT struct l_dir_watch *l_dir_watch_new(const char *pathname, - l_dir_watch_event_func_t function, - void *user_data, - l_dir_watch_destroy_func_t destroy) -{ - struct l_dir_watch *watch; - struct watch_desc *desc; - int fd; - - if (!pathname) - return NULL; - - watch = l_new(struct l_dir_watch, 1); - watch->function = function; - watch->user_data = user_data; - watch->destroy = destroy; - - desc = l_queue_find(watch_list, desc_match_pathname, pathname); - if (desc) - goto done; - - /* - * Returns the inotify file descriptor. It will create a new one - * if it doesn't exist yet or return the already opened one. - */ - fd = setup_inotify(); - if (fd < 0) { - l_free(watch); - return NULL; - } - - desc = l_new(struct watch_desc, 1); - - desc->wd = inotify_add_watch(fd, pathname, IN_ALL_EVENTS | - IN_ONLYDIR | - IN_DONT_FOLLOW | - IN_EXCL_UNLINK); - if (desc->wd < 0) { - /* - * If the setup_inotify() created the inotify file descriptor, - * then this will close it. Otherwise it will do nothing. - */ - shutdown_inotify(); - l_free(desc); - l_free(watch); - return NULL; - } - - desc->pathname = l_strdup(pathname); - desc->events = l_queue_new(); - desc->callbacks = l_queue_new(); - - l_queue_push_tail(watch_list, desc); - -done: - l_queue_push_tail(desc->callbacks, watch); - watch->desc = desc; - return watch; -} - -LIB_EXPORT void l_dir_watch_destroy(struct l_dir_watch *watch) -{ - struct watch_desc *desc; - int fd; - - if (!watch) - return; - - desc = watch->desc; - l_queue_remove(desc->callbacks, watch); - - /* - * As long as the watch descriptor has callbacks registered, it is - * still needed to be active. - */ - if (!l_queue_isempty(desc->callbacks)) - goto done; - - if (!l_queue_remove(watch_list, desc)) - goto done; - - fd = l_io_get_fd(inotify_io); - inotify_rm_watch(fd, desc->wd); - - l_queue_destroy(desc->callbacks, NULL); - l_queue_destroy(desc->events, free_event); - l_free(desc->pathname); - l_free(desc); - - /* - * When the number of watches goes to zero, then this will close - * the inotify file descriptor, otherwise it will do nothing. - */ - shutdown_inotify(); - -done: - if (watch->destroy) - watch->destroy(watch->user_data); - - l_free(watch); -} diff --git a/ell/dir.h b/ell/dir.h deleted file mode 100644 index 52e0f53..0000000 --- a/ell/dir.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2017 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_DIR_H -#define __ELL_DIR_H - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_dir_watch; - -enum l_dir_watch_event { - L_DIR_WATCH_EVENT_CREATED, - L_DIR_WATCH_EVENT_REMOVED, - L_DIR_WATCH_EVENT_MODIFIED, - L_DIR_WATCH_EVENT_ACCESSED, -}; - -typedef void (*l_dir_watch_event_func_t) (const char *filename, - enum l_dir_watch_event event, - void *user_data); -typedef void (*l_dir_watch_destroy_func_t) (void *user_data); - -struct l_dir_watch *l_dir_watch_new(const char *pathname, - l_dir_watch_event_func_t function, - void *user_data, - l_dir_watch_destroy_func_t destroy); -void l_dir_watch_destroy(struct l_dir_watch *watch); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_DIR_H */ diff --git a/ell/ecc-external.c b/ell/ecc-external.c deleted file mode 100644 index 1c118c2..0000000 --- a/ell/ecc-external.c +++ /dev/null @@ -1,951 +0,0 @@ -/* - * Copyright (c) 2013, Kenneth MacKay - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "private.h" -#include "ecc.h" -#include "ecc-private.h" -#include "random.h" - -typedef struct { - uint64_t m_low; - uint64_t m_high; -} uint128_t; - -static void vli_clear(uint64_t *vli, unsigned int ndigits) -{ - unsigned int i; - - for (i = 0; i < ndigits; i++) - vli[i] = 0; -} - -/* Returns true if vli == 0, false otherwise. */ -static bool vli_is_zero(const uint64_t *vli, unsigned int ndigits) -{ - unsigned int i; - - for (i = 0; i < ndigits; i++) { - if (vli[i]) - return false; - } - - return true; -} - -/* Returns nonzero if bit bit of vli is set. */ -static uint64_t vli_test_bit(const uint64_t *vli, unsigned int bit) -{ - return (vli[bit / 64] & ((uint64_t) 1 << (bit % 64))); -} - -/* Sets dest = src. */ -static void vli_set(uint64_t *dest, const uint64_t *src, unsigned int ndigits) -{ - unsigned int i; - - for (i = 0; i < ndigits; i++) - dest[i] = src[i]; -} - -/* Returns sign of left - right. */ -int _vli_cmp(const uint64_t *left, const uint64_t *right, unsigned int ndigits) -{ - int i; - - for (i = ndigits - 1; i >= 0; i--) { - if (left[i] > right[i]) - return 1; - else if (left[i] < right[i]) - return -1; - } - - return 0; -} - -/* Computes result = in << c, returning carry. Can modify in place - * (if result == in). 0 < shift < 64. - */ -static uint64_t vli_lshift(uint64_t *result, const uint64_t *in, - unsigned int shift, - unsigned int ndigits) -{ - uint64_t carry = 0; - unsigned int i; - - for (i = 0; i < ndigits; i++) { - uint64_t temp = in[i]; - - result[i] = (temp << shift) | carry; - carry = temp >> (64 - shift); - } - - return carry; -} - -/* Computes vli = vli >> 1. */ -void _vli_rshift1(uint64_t *vli, unsigned int ndigits) -{ - uint64_t *end = vli; - uint64_t carry = 0; - - vli += ndigits; - - while (vli-- > end) { - uint64_t temp = *vli; - *vli = (temp >> 1) | carry; - carry = temp << 63; - } -} - -/* Computes result = left + right, returning carry. Can modify in place. */ -static uint64_t vli_add(uint64_t *result, const uint64_t *left, - const uint64_t *right, - unsigned int ndigits) -{ - uint64_t carry = 0; - unsigned int i; - - for (i = 0; i < ndigits; i++) { - uint64_t sum; - - sum = left[i] + right[i] + carry; - if (sum != left[i]) - carry = (sum < left[i]); - - result[i] = sum; - } - - return carry; -} - -/* Computes result = left - right, returning borrow. Can modify in place. */ -uint64_t _vli_sub(uint64_t *result, const uint64_t *left, - const uint64_t *right, - unsigned int ndigits) -{ - uint64_t borrow = 0; - unsigned int i; - - for (i = 0; i < ndigits; i++) { - uint64_t diff; - - diff = left[i] - right[i] - borrow; - if (diff != left[i]) - borrow = (diff > left[i]); - - result[i] = diff; - } - - return borrow; -} - -static uint128_t mul_64_64(uint64_t left, uint64_t right) -{ - uint64_t a0 = left & 0xffffffffull; - uint64_t a1 = left >> 32; - uint64_t b0 = right & 0xffffffffull; - uint64_t b1 = right >> 32; - uint64_t m0 = a0 * b0; - uint64_t m1 = a0 * b1; - uint64_t m2 = a1 * b0; - uint64_t m3 = a1 * b1; - uint128_t result; - - m2 += (m0 >> 32); - m2 += m1; - - /* Overflow */ - if (m2 < m1) - m3 += 0x100000000ull; - - result.m_low = (m0 & 0xffffffffull) | (m2 << 32); - result.m_high = m3 + (m2 >> 32); - - return result; -} - -static uint128_t add_128_128(uint128_t a, uint128_t b) -{ - uint128_t result; - - result.m_low = a.m_low + b.m_low; - result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low); - - return result; -} - -static void vli_mult(uint64_t *result, const uint64_t *left, - const uint64_t *right, - unsigned int ndigits) -{ - uint128_t r01 = { 0, 0 }; - uint64_t r2 = 0; - unsigned int i, k; - - /* Compute each digit of result in sequence, maintaining the - * carries. - */ - for (k = 0; k < ndigits * 2 - 1; k++) { - unsigned int min; - - if (k < ndigits) - min = 0; - else - min = (k + 1) - ndigits; - - for (i = min; i <= k && i < ndigits; i++) { - uint128_t product; - - product = mul_64_64(left[i], right[k - i]); - - r01 = add_128_128(r01, product); - r2 += (r01.m_high < product.m_high); - } - - result[k] = r01.m_low; - r01.m_low = r01.m_high; - r01.m_high = r2; - r2 = 0; - } - - result[ndigits * 2 - 1] = r01.m_low; -} - -static void vli_square(uint64_t *result, const uint64_t *left, - unsigned int ndigits) -{ - uint128_t r01 = { 0, 0 }; - uint64_t r2 = 0; - unsigned int i, k; - - for (k = 0; k < ndigits * 2 - 1; k++) { - unsigned int min; - - if (k < ndigits) - min = 0; - else - min = (k + 1) - ndigits; - - for (i = min; i <= k && i <= k - i; i++) { - uint128_t product; - - product = mul_64_64(left[i], left[k - i]); - - if (i < k - i) { - r2 += product.m_high >> 63; - product.m_high = (product.m_high << 1) | - (product.m_low >> 63); - product.m_low <<= 1; - } - - r01 = add_128_128(r01, product); - r2 += (r01.m_high < product.m_high); - } - - result[k] = r01.m_low; - r01.m_low = r01.m_high; - r01.m_high = r2; - r2 = 0; - } - - result[ndigits * 2 - 1] = r01.m_low; -} - -/* Computes result = (left + right) % mod. - * Assumes that left < mod and right < mod, result != mod. - */ -void _vli_mod_add(uint64_t *result, const uint64_t *left, - const uint64_t *right, const uint64_t *mod, - unsigned int ndigits) -{ - uint64_t carry; - - carry = vli_add(result, left, right, ndigits); - - /* result > mod (result = mod + remainder), so subtract mod to - * get remainder. - */ - if (carry || _vli_cmp(result, mod, ndigits) >= 0) - _vli_sub(result, result, mod, ndigits); -} - -/* Computes result = (left - right) % mod. - * Assumes that left < mod and right < mod, result != mod. - */ -void _vli_mod_sub(uint64_t *result, const uint64_t *left, - const uint64_t *right, const uint64_t *mod, - unsigned int ndigits) -{ - uint64_t borrow = _vli_sub(result, left, right, ndigits); - - /* In this case, p_result == -diff == (max int) - diff. - * Since -x % d == d - x, we can get the correct result from - * result + mod (with overflow). - */ - if (borrow) - vli_add(result, result, mod, ndigits); -} - -/* Computes p_result = p_product % curve_p. - * See algorithm 5 and 6 from - * http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf - */ -static void vli_mmod_fast_192(uint64_t *result, const uint64_t *product, - const uint64_t *curve_prime, uint64_t *tmp) -{ - const unsigned int ndigits = 3; - int carry; - - vli_set(result, product, ndigits); - - vli_set(tmp, &product[3], ndigits); - carry = vli_add(result, result, tmp, ndigits); - - tmp[0] = 0; - tmp[1] = product[3]; - tmp[2] = product[4]; - carry += vli_add(result, result, tmp, ndigits); - - tmp[0] = tmp[1] = product[5]; - tmp[2] = 0; - carry += vli_add(result, result, tmp, ndigits); - - while (carry || _vli_cmp(curve_prime, result, ndigits) != 1) - carry -= _vli_sub(result, result, curve_prime, ndigits); -} - -/* Computes result = product % curve_prime - * from http://www.nsa.gov/ia/_files/nist-routines.pdf - */ -static void vli_mmod_fast_256(uint64_t *result, const uint64_t *product, - const uint64_t *curve_prime, uint64_t *tmp) -{ - int carry; - const unsigned int ndigits = 4; - - /* t */ - vli_set(result, product, ndigits); - - /* s1 */ - tmp[0] = 0; - tmp[1] = product[5] & 0xffffffff00000000ull; - tmp[2] = product[6]; - tmp[3] = product[7]; - carry = vli_lshift(tmp, tmp, 1, ndigits); - carry += vli_add(result, result, tmp, ndigits); - - /* s2 */ - tmp[1] = product[6] << 32; - tmp[2] = (product[6] >> 32) | (product[7] << 32); - tmp[3] = product[7] >> 32; - carry += vli_lshift(tmp, tmp, 1, ndigits); - carry += vli_add(result, result, tmp, ndigits); - - /* s3 */ - tmp[0] = product[4]; - tmp[1] = product[5] & 0xffffffff; - tmp[2] = 0; - tmp[3] = product[7]; - carry += vli_add(result, result, tmp, ndigits); - - /* s4 */ - tmp[0] = (product[4] >> 32) | (product[5] << 32); - tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull); - tmp[2] = product[7]; - tmp[3] = (product[6] >> 32) | (product[4] << 32); - carry += vli_add(result, result, tmp, ndigits); - - /* d1 */ - tmp[0] = (product[5] >> 32) | (product[6] << 32); - tmp[1] = (product[6] >> 32); - tmp[2] = 0; - tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32); - carry -= _vli_sub(result, result, tmp, ndigits); - - /* d2 */ - tmp[0] = product[6]; - tmp[1] = product[7]; - tmp[2] = 0; - tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull); - carry -= _vli_sub(result, result, tmp, ndigits); - - /* d3 */ - tmp[0] = (product[6] >> 32) | (product[7] << 32); - tmp[1] = (product[7] >> 32) | (product[4] << 32); - tmp[2] = (product[4] >> 32) | (product[5] << 32); - tmp[3] = (product[6] << 32); - carry -= _vli_sub(result, result, tmp, ndigits); - - /* d4 */ - tmp[0] = product[7]; - tmp[1] = product[4] & 0xffffffff00000000ull; - tmp[2] = product[5]; - tmp[3] = product[6] & 0xffffffff00000000ull; - carry -= _vli_sub(result, result, tmp, ndigits); - - if (carry < 0) { - do { - carry += vli_add(result, result, curve_prime, ndigits); - } while (carry < 0); - } else { - while (carry || _vli_cmp(curve_prime, result, ndigits) != 1) - carry -= _vli_sub(result, result, curve_prime, ndigits); - } -} - -/* - * The NIST algorithms define S values, which are comprised of 32 bit C values - * of the original product we are trying to reduce. Since we are working with - * 64 bit 'digits', we need to convert these C values into 64 bit chunks. This - * macro mainly makes code readability easier since we can directly pass the - * two C indexes (h and l). Some of these C values are zero, which is also a - * value C index. In this case -1 should be passed to indicate zero. - */ -#define ECC_SET_S(prod, h, l) ({ \ - uint64_t r = 0; \ - if (h == -1) { \ - /* zero, don't do anything */ \ - } else if (h & 1) \ - r |= (prod[h / 2] & 0xffffffff00000000ull); \ - else \ - r |= (prod[h / 2] << 32); \ - if (l == -1) { \ - /* zero, don't do anything */ \ - } else if (l & 1) \ - r |= (prod[l / 2] >> 32); \ - else \ - r |= (prod[l / 2] & 0xffffffff); \ - r; \ -}) - -static void vli_mmod_fast_384(uint64_t *result, const uint64_t *product, - const uint64_t *curve_prime, uint64_t *tmp) -{ - int carry; - const unsigned int ndigits = 6; - - /* t */ - vli_set(result, product, ndigits); - - /* s1 */ - tmp[0] = 0; - tmp[1] = 0; - tmp[2] = ECC_SET_S(product, 22, 21); - tmp[3] = ECC_SET_S(product, -1, 23); - tmp[4] = 0; - tmp[5] = 0; - carry = vli_lshift(tmp, tmp, 1, ndigits); - carry += vli_add(result, result, tmp, ndigits); - - /* s2 */ - tmp[0] = product[6]; - tmp[1] = product[7]; - tmp[2] = product[8]; - tmp[3] = product[9]; - tmp[4] = product[10]; - tmp[5] = product[11]; - carry += vli_add(result, result, tmp, ndigits); - - /* s3 */ - tmp[0] = ECC_SET_S(product, 22, 21); - tmp[1] = ECC_SET_S(product, 12, 23); - tmp[2] = ECC_SET_S(product, 14, 13); - tmp[3] = ECC_SET_S(product, 16, 15); - tmp[4] = ECC_SET_S(product, 18, 17); - tmp[5] = ECC_SET_S(product, 20, 19); - carry += vli_add(result, result, tmp, ndigits); - - /* s4 */ - tmp[0] = ECC_SET_S(product, 23, -1); - tmp[1] = ECC_SET_S(product, 20, -1); - tmp[2] = ECC_SET_S(product, 13, 12); - tmp[3] = ECC_SET_S(product, 15, 14); - tmp[4] = ECC_SET_S(product, 17, 16); - tmp[5] = ECC_SET_S(product, 19, 18); - carry += vli_add(result, result, tmp, ndigits); - - /* s5 */ - tmp[0] = 0; - tmp[1] = 0; - tmp[2] = ECC_SET_S(product, 21, 20); - tmp[3] = ECC_SET_S(product, 23, 22); - tmp[4] = 0; - tmp[5] = 0; - carry += vli_add(result, result, tmp, ndigits); - - /* s6 */ - tmp[0] = ECC_SET_S(product, -1, 20); - tmp[1] = ECC_SET_S(product, 21, -1); - tmp[2] = ECC_SET_S(product, 23, 22); - tmp[3] = 0; - tmp[4] = 0; - tmp[5] = 0; - carry += vli_add(result, result, tmp, ndigits); - - /* s7 */ - tmp[0] = ECC_SET_S(product, 12, 23); - tmp[1] = ECC_SET_S(product, 14, 13); - tmp[2] = ECC_SET_S(product, 16, 15); - tmp[3] = ECC_SET_S(product, 18, 17); - tmp[4] = ECC_SET_S(product, 20, 19); - tmp[5] = ECC_SET_S(product, 22, 21); - carry -= _vli_sub(result, result, tmp, ndigits); - - /* s8 */ - tmp[0] = ECC_SET_S(product, 20, -1); - tmp[1] = ECC_SET_S(product, 22, 21); - tmp[2] = ECC_SET_S(product, -1, 23); - tmp[3] = 0; - tmp[4] = 0; - tmp[5] = 0; - carry -= _vli_sub(result, result, tmp, ndigits); - - /* s9 */ - tmp[0] = 0; - tmp[1] = ECC_SET_S(product, 23, -1); - tmp[2] = ECC_SET_S(product, -1, 23); - tmp[3] = 0; - tmp[4] = 0; - tmp[5] = 0; - carry -= _vli_sub(result, result, tmp, ndigits); - - if (carry < 0) { - do { - carry += vli_add(result, result, curve_prime, ndigits); - } while (carry < 0); - } else { - while (carry || _vli_cmp(curve_prime, result, ndigits) != 1) - carry -= _vli_sub(result, result, curve_prime, ndigits); - } -} - -/* Computes result = product % curve_prime - * from http://www.nsa.gov/ia/_files/nist-routines.pdf -*/ -static bool vli_mmod_fast(uint64_t *result, uint64_t *product, - const uint64_t *curve_prime, - unsigned int ndigits) -{ - uint64_t tmp[2 * L_ECC_MAX_DIGITS]; - - switch (ndigits) { - case 3: - vli_mmod_fast_192(result, product, curve_prime, tmp); - break; - case 4: - vli_mmod_fast_256(result, product, curve_prime, tmp); - break; - case 6: - vli_mmod_fast_384(result, product, curve_prime, tmp); - break; - default: - return false; - } - - return true; -} - -/* Computes result = (left * right) % curve_p. */ -void _vli_mod_mult_fast(uint64_t *result, const uint64_t *left, - const uint64_t *right, const uint64_t *curve_prime, - unsigned int ndigits) -{ - uint64_t product[2 * L_ECC_MAX_DIGITS]; - - vli_mult(product, left, right, ndigits); - vli_mmod_fast(result, product, curve_prime, ndigits); -} - -/* Computes result = left^2 % curve_p. */ -void _vli_mod_square_fast(uint64_t *result, const uint64_t *left, - const uint64_t *curve_prime, - unsigned int ndigits) -{ - uint64_t product[2 * L_ECC_MAX_DIGITS]; - - vli_square(product, left, ndigits); - vli_mmod_fast(result, product, curve_prime, ndigits); -} - -#define EVEN(vli) (!(vli[0] & 1)) -/* Computes result = (1 / p_input) % mod. All VLIs are the same size. - * See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" - * https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf - */ -void _vli_mod_inv(uint64_t *result, const uint64_t *input, - const uint64_t *mod, - unsigned int ndigits) -{ - uint64_t a[L_ECC_MAX_DIGITS], b[L_ECC_MAX_DIGITS]; - uint64_t u[L_ECC_MAX_DIGITS], v[L_ECC_MAX_DIGITS]; - uint64_t carry; - int cmp_result; - - if (vli_is_zero(input, ndigits)) { - vli_clear(result, ndigits); - return; - } - - vli_set(a, input, ndigits); - vli_set(b, mod, ndigits); - vli_clear(u, ndigits); - u[0] = 1; - vli_clear(v, ndigits); - - while ((cmp_result = _vli_cmp(a, b, ndigits)) != 0) { - carry = 0; - - if (EVEN(a)) { - _vli_rshift1(a, ndigits); - - if (!EVEN(u)) - carry = vli_add(u, u, mod, ndigits); - - _vli_rshift1(u, ndigits); - if (carry) - u[ndigits - 1] |= 0x8000000000000000ull; - } else if (EVEN(b)) { - _vli_rshift1(b, ndigits); - - if (!EVEN(v)) - carry = vli_add(v, v, mod, ndigits); - - _vli_rshift1(v, ndigits); - if (carry) - v[ndigits - 1] |= 0x8000000000000000ull; - } else if (cmp_result > 0) { - _vli_sub(a, a, b, ndigits); - _vli_rshift1(a, ndigits); - - if (_vli_cmp(u, v, ndigits) < 0) - vli_add(u, u, mod, ndigits); - - _vli_sub(u, u, v, ndigits); - if (!EVEN(u)) - carry = vli_add(u, u, mod, ndigits); - - _vli_rshift1(u, ndigits); - if (carry) - u[ndigits - 1] |= 0x8000000000000000ull; - } else { - _vli_sub(b, b, a, ndigits); - _vli_rshift1(b, ndigits); - - if (_vli_cmp(v, u, ndigits) < 0) - vli_add(v, v, mod, ndigits); - - _vli_sub(v, v, u, ndigits); - if (!EVEN(v)) - carry = vli_add(v, v, mod, ndigits); - - _vli_rshift1(v, ndigits); - if (carry) - v[ndigits - 1] |= 0x8000000000000000ull; - } - } - - vli_set(result, u, ndigits); -} - -/* ------ Point operations ------ */ - -/* Point multiplication algorithm using Montgomery's ladder with co-Z - * coordinates. From http://eprint.iacr.org/2011/338.pdf - */ - -/* Double in place */ -static void ecc_point_double_jacobian(uint64_t *x1, uint64_t *y1, uint64_t *z1, - const uint64_t *curve_prime, - unsigned int ndigits) -{ - /* t1 = x, t2 = y, t3 = z */ - uint64_t t4[L_ECC_MAX_DIGITS]; - uint64_t t5[L_ECC_MAX_DIGITS]; - - if (vli_is_zero(z1, ndigits)) - return; - - /* t4 = y1^2 */ - _vli_mod_square_fast(t4, y1, curve_prime, ndigits); - /* t5 = x1*y1^2 = A */ - _vli_mod_mult_fast(t5, x1, t4, curve_prime, ndigits); - /* t4 = y1^4 */ - _vli_mod_square_fast(t4, t4, curve_prime, ndigits); - /* t2 = y1*z1 = z3 */ - _vli_mod_mult_fast(y1, y1, z1, curve_prime, ndigits); - /* t3 = z1^2 */ - _vli_mod_square_fast(z1, z1, curve_prime, ndigits); - - /* t1 = x1 + z1^2 */ - _vli_mod_add(x1, x1, z1, curve_prime, ndigits); - /* t3 = 2*z1^2 */ - _vli_mod_add(z1, z1, z1, curve_prime, ndigits); - /* t3 = x1 - z1^2 */ - _vli_mod_sub(z1, x1, z1, curve_prime, ndigits); - /* t1 = x1^2 - z1^4 */ - _vli_mod_mult_fast(x1, x1, z1, curve_prime, ndigits); - - /* t3 = 2*(x1^2 - z1^4) */ - _vli_mod_add(z1, x1, x1, curve_prime, ndigits); - /* t1 = 3*(x1^2 - z1^4) */ - _vli_mod_add(x1, x1, z1, curve_prime, ndigits); - if (vli_test_bit(x1, 0)) { - uint64_t carry = vli_add(x1, x1, curve_prime, ndigits); - _vli_rshift1(x1, ndigits); - x1[ndigits - 1] |= carry << 63; - } else { - _vli_rshift1(x1, ndigits); - } - /* t1 = 3/2*(x1^2 - z1^4) = B */ - - /* t3 = B^2 */ - _vli_mod_square_fast(z1, x1, curve_prime, ndigits); - /* t3 = B^2 - A */ - _vli_mod_sub(z1, z1, t5, curve_prime, ndigits); - /* t3 = B^2 - 2A = x3 */ - _vli_mod_sub(z1, z1, t5, curve_prime, ndigits); - /* t5 = A - x3 */ - _vli_mod_sub(t5, t5, z1, curve_prime, ndigits); - /* t1 = B * (A - x3) */ - _vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits); - /* t4 = B * (A - x3) - y1^4 = y3 */ - _vli_mod_sub(t4, x1, t4, curve_prime, ndigits); - - vli_set(x1, z1, ndigits); - vli_set(z1, y1, ndigits); - vli_set(y1, t4, ndigits); -} - -/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ -static void apply_z(uint64_t *x1, uint64_t *y1, uint64_t *z, - const uint64_t *curve_prime, unsigned int ndigits) -{ - uint64_t t1[L_ECC_MAX_DIGITS]; - - _vli_mod_square_fast(t1, z, curve_prime, ndigits); /* z^2 */ - _vli_mod_mult_fast(x1, x1, t1, curve_prime, ndigits); /* x1 * z^2 */ - _vli_mod_mult_fast(t1, t1, z, curve_prime, ndigits); /* z^3 */ - _vli_mod_mult_fast(y1, y1, t1, curve_prime, ndigits); /* y1 * z^3 */ -} - -/* P = (x1, y1) => 2P, (x2, y2) => P' */ -static void xycz_initial_double(uint64_t *x1, uint64_t *y1, uint64_t *x2, - uint64_t *y2, uint64_t *p_initial_z, - const uint64_t *curve_prime, - unsigned int ndigits) -{ - uint64_t z[L_ECC_MAX_DIGITS]; - - vli_set(x2, x1, ndigits); - vli_set(y2, y1, ndigits); - - vli_clear(z, ndigits); - z[0] = 1; - - if (p_initial_z) - vli_set(z, p_initial_z, ndigits); - - apply_z(x1, y1, z, curve_prime, ndigits); - - ecc_point_double_jacobian(x1, y1, z, curve_prime, ndigits); - - apply_z(x2, y2, z, curve_prime, ndigits); -} - -/* Input P = (x1, y1, Z), Q = (x2, y2, Z) - * Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) - * or P => P', Q => P + Q - */ -static void xycz_add(uint64_t *x1, uint64_t *y1, uint64_t *x2, uint64_t *y2, - const uint64_t *curve_prime, unsigned int ndigits) -{ - /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ - uint64_t t5[L_ECC_MAX_DIGITS]; - - /* t5 = x2 - x1 */ - _vli_mod_sub(t5, x2, x1, curve_prime, ndigits); - /* t5 = (x2 - x1)^2 = A */ - _vli_mod_square_fast(t5, t5, curve_prime, ndigits); - /* t1 = x1*A = B */ - _vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits); - /* t3 = x2*A = C */ - _vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits); - /* t4 = y2 - y1 */ - _vli_mod_sub(y2, y2, y1, curve_prime, ndigits); - /* t5 = (y2 - y1)^2 = D */ - _vli_mod_square_fast(t5, y2, curve_prime, ndigits); - - /* t5 = D - B */ - _vli_mod_sub(t5, t5, x1, curve_prime, ndigits); - /* t5 = D - B - C = x3 */ - _vli_mod_sub(t5, t5, x2, curve_prime, ndigits); - /* t3 = C - B */ - _vli_mod_sub(x2, x2, x1, curve_prime, ndigits); - /* t2 = y1*(C - B) */ - _vli_mod_mult_fast(y1, y1, x2, curve_prime, ndigits); - /* t3 = B - x3 */ - _vli_mod_sub(x2, x1, t5, curve_prime, ndigits); - /* t4 = (y2 - y1)*(B - x3) */ - _vli_mod_mult_fast(y2, y2, x2, curve_prime, ndigits); - /* t4 = y3 */ - _vli_mod_sub(y2, y2, y1, curve_prime, ndigits); - - vli_set(x2, t5, ndigits); -} - -/* Input P = (x1, y1, Z), Q = (x2, y2, Z) - * Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) - * or P => P - Q, Q => P + Q - */ -static void xycz_add_c(uint64_t *x1, uint64_t *y1, uint64_t *x2, uint64_t *y2, - const uint64_t *curve_prime, unsigned int ndigits) -{ - /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ - uint64_t t5[L_ECC_MAX_DIGITS]; - uint64_t t6[L_ECC_MAX_DIGITS]; - uint64_t t7[L_ECC_MAX_DIGITS]; - - /* t5 = x2 - x1 */ - _vli_mod_sub(t5, x2, x1, curve_prime, ndigits); - /* t5 = (x2 - x1)^2 = A */ - _vli_mod_square_fast(t5, t5, curve_prime, ndigits); - /* t1 = x1*A = B */ - _vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits); - /* t3 = x2*A = C */ - _vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits); - /* t4 = y2 + y1 */ - _vli_mod_add(t5, y2, y1, curve_prime, ndigits); - /* t4 = y2 - y1 */ - _vli_mod_sub(y2, y2, y1, curve_prime, ndigits); - - /* t6 = C - B */ - _vli_mod_sub(t6, x2, x1, curve_prime, ndigits); - /* t2 = y1 * (C - B) */ - _vli_mod_mult_fast(y1, y1, t6, curve_prime, ndigits); - /* t6 = B + C */ - _vli_mod_add(t6, x1, x2, curve_prime, ndigits); - /* t3 = (y2 - y1)^2 */ - _vli_mod_square_fast(x2, y2, curve_prime, ndigits); - /* t3 = x3 */ - _vli_mod_sub(x2, x2, t6, curve_prime, ndigits); - - /* t7 = B - x3 */ - _vli_mod_sub(t7, x1, x2, curve_prime, ndigits); - /* t4 = (y2 - y1)*(B - x3) */ - _vli_mod_mult_fast(y2, y2, t7, curve_prime, ndigits); - /* t4 = y3 */ - _vli_mod_sub(y2, y2, y1, curve_prime, ndigits); - - /* t7 = (y2 + y1)^2 = F */ - _vli_mod_square_fast(t7, t5, curve_prime, ndigits); - /* t7 = x3' */ - _vli_mod_sub(t7, t7, t6, curve_prime, ndigits); - /* t6 = x3' - B */ - _vli_mod_sub(t6, t7, x1, curve_prime, ndigits); - /* t6 = (y2 + y1)*(x3' - B) */ - _vli_mod_mult_fast(t6, t6, t5, curve_prime, ndigits); - /* t2 = y3' */ - _vli_mod_sub(y1, t6, y1, curve_prime, ndigits); - - vli_set(x1, t7, ndigits); -} - -void _ecc_point_mult(struct l_ecc_point *result, - const struct l_ecc_point *point, const uint64_t *scalar, - uint64_t *initial_z, const uint64_t *curve_prime) -{ - /* R0 and R1 */ - const struct l_ecc_curve *curve = point->curve; - uint64_t rx[2][L_ECC_MAX_DIGITS]; - uint64_t ry[2][L_ECC_MAX_DIGITS]; - uint64_t z[L_ECC_MAX_DIGITS]; - uint64_t sk[2][L_ECC_MAX_DIGITS]; - int i, nb; - unsigned int ndigits = curve->ndigits; - int num_bits; - int carry; - - carry = vli_add(sk[0], scalar, curve->n, ndigits); - vli_add(sk[1], sk[0], curve->n, ndigits); - scalar = sk[!carry]; - num_bits = sizeof(uint64_t) * ndigits * 8 + 1; - - vli_set(rx[1], point->x, ndigits); - vli_set(ry[1], point->y, ndigits); - - xycz_initial_double(rx[1], ry[1], rx[0], ry[0], initial_z, curve_prime, - ndigits); - - for (i = num_bits - 2; i > 0; i--) { - nb = !vli_test_bit(scalar, i); - xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve_prime, - ndigits); - xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve_prime, - ndigits); - } - - nb = !vli_test_bit(scalar, 0); - xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve_prime, - ndigits); - - /* Find final 1/Z value. */ - /* X1 - X0 */ - _vli_mod_sub(z, rx[1], rx[0], curve_prime, ndigits); - /* Yb * (X1 - X0) */ - _vli_mod_mult_fast(z, z, ry[1 - nb], curve_prime, ndigits); - /* xP * Yb * (X1 - X0) */ - _vli_mod_mult_fast(z, z, point->x, curve_prime, ndigits); - - /* 1 / (xP * Yb * (X1 - X0)) */ - _vli_mod_inv(z, z, curve_prime, ndigits); - - /* yP / (xP * Yb * (X1 - X0)) */ - _vli_mod_mult_fast(z, z, point->y, curve_prime, ndigits); - /* Xb * yP / (xP * Yb * (X1 - X0)) */ - _vli_mod_mult_fast(z, z, rx[1 - nb], curve_prime, ndigits); - /* End 1/Z calculation */ - - xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve_prime, ndigits); - - apply_z(rx[0], ry[0], z, curve_prime, ndigits); - - vli_set(result->x, rx[0], ndigits); - vli_set(result->y, ry[0], ndigits); -} - -/* Returns true if p_point is the point at infinity, false otherwise. */ -bool _ecc_point_is_zero(const struct l_ecc_point *point) -{ - return (vli_is_zero(point->x, point->curve->ndigits) && - vli_is_zero(point->y, point->curve->ndigits)); -} diff --git a/ell/ecc-private.h b/ell/ecc-private.h deleted file mode 100644 index 0e85d98..0000000 --- a/ell/ecc-private.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include - -#include "ecc.h" - -struct l_ecc_curve; - -struct l_ecc_point { - uint64_t x[L_ECC_MAX_DIGITS]; - uint64_t y[L_ECC_MAX_DIGITS]; - const struct l_ecc_curve *curve; -}; - -struct l_ecc_curve { - unsigned int ndigits; - unsigned int ike_group; - unsigned int tls_group; - const char *name; - struct l_ecc_point g; - uint64_t p[L_ECC_MAX_DIGITS]; - uint64_t n[L_ECC_MAX_DIGITS]; - uint64_t b[L_ECC_MAX_DIGITS]; -}; - -struct l_ecc_scalar { - uint64_t c[L_ECC_MAX_DIGITS]; - const struct l_ecc_curve *curve; -}; - -void _ecc_be2native(uint64_t *dest, const uint64_t *bytes, - unsigned int ndigits); - -void _ecc_native2be(uint64_t *dest, const uint64_t *native, - unsigned int ndigits); - -void _vli_mod_inv(uint64_t *result, const uint64_t *input, const uint64_t *mod, - unsigned int ndigits); - -void _vli_mod_sub(uint64_t *result, const uint64_t *left, const uint64_t *right, - const uint64_t *curve_prime, unsigned int ndigits); - -void _vli_mod_add(uint64_t *result, const uint64_t *left, const uint64_t *right, - const uint64_t *curve_prime, unsigned int ndigits); - -void _vli_rshift1(uint64_t *vli, unsigned int ndigits); - -void _vli_mod_mult_fast(uint64_t *result, const uint64_t *left, - const uint64_t *right, const uint64_t *curve_prime, - unsigned int ndigits); -void _vli_mod_square_fast(uint64_t *result, const uint64_t *left, - const uint64_t *curve_prime, - unsigned int ndigits); -void _vli_mod_exp(uint64_t *result, uint64_t *base, uint64_t *exp, - const uint64_t *mod, unsigned int ndigits); - -int _vli_cmp(const uint64_t *left, const uint64_t *right, unsigned int ndigits); - -uint64_t _vli_sub(uint64_t *result, const uint64_t *left, - const uint64_t *right, - unsigned int ndigits); - -int _vli_legendre(uint64_t *val, const uint64_t *p, unsigned int ndigits); - -bool _ecc_point_is_zero(const struct l_ecc_point *point); - -void _ecc_calculate_p2(const struct l_ecc_curve *curve, uint64_t *p2); - -bool _ecc_compute_y(const struct l_ecc_curve *curve, uint64_t *y, uint64_t *x); - -void _ecc_point_mult(struct l_ecc_point *result, - const struct l_ecc_point *point, const uint64_t *scalar, - uint64_t *initial_z, const uint64_t *curve_prime); -void _ecc_point_add(struct l_ecc_point *ret, const struct l_ecc_point *p, - const struct l_ecc_point *q, - const uint64_t *curve_prime); -struct l_ecc_scalar *_ecc_constant_new(const struct l_ecc_curve *curve, - const void *buf, size_t len); diff --git a/ell/ecc.c b/ell/ecc.c deleted file mode 100644 index d0c7393..0000000 --- a/ell/ecc.c +++ /dev/null @@ -1,760 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include -#include -#include -#include - -#include "ecc.h" -#include "ecc-private.h" -#include "random.h" -#include "private.h" -#include "missing.h" - -/* - * RFC 5114 - Section 2.6 256-bit Random ECP Group - */ -#define P256_CURVE_P { 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull, \ - 0x0000000000000000ull, 0xFFFFFFFF00000001ull } -#define P256_CURVE_GX { 0xF4A13945D898C296ull, 0x77037D812DEB33A0ull, \ - 0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull } -#define P256_CURVE_GY { 0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull, \ - 0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull } -#define P256_CURVE_N { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull, \ - 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull } -#define P256_CURVE_B { 0x3BCE3C3E27D2604Bull, 0x651D06B0CC53B0F6ull, \ - 0xB3EBBD55769886BCull, 0x5AC635D8AA3A93E7ull } - -static const struct l_ecc_curve p256 = { - .name = "secp256r1", - .ike_group = 19, - .tls_group = 23, - .ndigits = 4, - .g = { - .x = P256_CURVE_GX, - .y = P256_CURVE_GY, - .curve = &p256 - }, - .p = P256_CURVE_P, - .n = P256_CURVE_N, - .b = P256_CURVE_B, -}; - -/* - * RFC 5114 - Section 2.7 384-bit Random ECP Group - */ -#define P384_CURVE_P { 0x00000000FFFFFFFFull, 0xFFFFFFFF00000000ull, \ - 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull, \ - 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull } -#define P384_CURVE_GX { 0x3A545E3872760AB7ull, 0x5502F25DBF55296Cull, \ - 0x59F741E082542A38ull, 0x6E1D3B628BA79B98ull, \ - 0x8EB1C71EF320AD74ull, 0xAA87CA22BE8B0537ull } -#define P384_CURVE_GY { 0x7A431D7C90EA0E5Full, 0x0A60B1CE1D7E819Dull, \ - 0xE9DA3113B5F0B8C0ull, 0xF8F41DBD289A147Cull, \ - 0x5D9E98BF9292DC29ull, 0x3617DE4A96262C6Full } -#define P384_CURVE_N { 0xECEC196ACCC52973ull, 0x581A0DB248B0A77Aull, \ - 0xC7634D81F4372DDFull, 0xFFFFFFFFFFFFFFFFull, \ - 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull } -#define P384_CURVE_B { 0x2A85C8EDD3EC2AEFull, 0xC656398D8A2ED19Dull, \ - 0x0314088F5013875Aull, 0x181D9C6EFE814112ull, \ - 0x988E056BE3F82D19ull, 0xB3312FA7E23EE7E4ull } - -static const struct l_ecc_curve p384 = { - .name = "secp384r1", - .ike_group = 20, - .tls_group = 24, - .ndigits = 6, - .g = { - .x = P384_CURVE_GX, - .y = P384_CURVE_GY, - .curve = &p384 - }, - .p = P384_CURVE_P, - .n = P384_CURVE_N, - .b = P384_CURVE_B -}; - -static const struct l_ecc_curve *curves[] = { - &p256, - &p384, -}; - -LIB_EXPORT const struct l_ecc_curve *l_ecc_curve_get(const char *name) -{ - int i; - - if (unlikely(!name)) - return NULL; - - for (i = 0; curves[i]; i++) { - if (!strcmp(curves[i]->name, name)) - return curves[i]; - } - - return NULL; -} - -LIB_EXPORT const char *l_ecc_curve_get_name(const struct l_ecc_curve *curve) -{ - if (unlikely(!curve)) - return NULL; - - return curve->name; -} - -LIB_EXPORT size_t l_ecc_curve_get_scalar_bytes(const struct l_ecc_curve *curve) -{ - if (unlikely(!curve)) - return 0; - - return curve->ndigits * 8; -} - -LIB_EXPORT const struct l_ecc_curve *l_ecc_curve_get_ike_group( - unsigned int group) -{ - unsigned int i; - - for (i = 0; i < L_ARRAY_SIZE(curves); i++) { - if (curves[i]->ike_group == group) - return curves[i]; - } - - return NULL; -} - -LIB_EXPORT const struct l_ecc_curve *l_ecc_curve_get_tls_group( - unsigned int group) -{ - unsigned int i; - - for (i = 0; i < L_ARRAY_SIZE(curves); i++) { - if (curves[i]->tls_group == group) - return curves[i]; - } - - return NULL; -} - -LIB_EXPORT const unsigned int *l_ecc_curve_get_supported_ike_groups(void) -{ - static unsigned int supported_ike_groups[L_ARRAY_SIZE(curves) + 1]; - static bool ike_first = true; - - if (ike_first) { - unsigned int i; - - for (i = 0; i < L_ARRAY_SIZE(curves); i++) - supported_ike_groups[i] = curves[i]->ike_group; - - supported_ike_groups[i] = 0; - ike_first = false; - } - - return supported_ike_groups; -} - -LIB_EXPORT const unsigned int *l_ecc_curve_get_supported_tls_groups(void) -{ - static unsigned int supported_tls_groups[L_ARRAY_SIZE(curves) + 1]; - static bool tls_first = true; - - if (tls_first) { - unsigned int i; - - for (i = 0; i < L_ARRAY_SIZE(curves); i++) - supported_tls_groups[i] = curves[i]->tls_group; - - supported_tls_groups[i] = 0; - tls_first = false; - } - - return supported_tls_groups; -} - -static bool ecc_valid_point(struct l_ecc_point *point) -{ - const struct l_ecc_curve *curve = point->curve; - uint64_t tmp1[L_ECC_MAX_DIGITS]; - uint64_t tmp2[L_ECC_MAX_DIGITS]; - uint64_t _3[L_ECC_MAX_DIGITS] = { 3 }; /* -a = 3 */ - unsigned int ndigits = curve->ndigits; - - /* The point at infinity is invalid. */ - if (_ecc_point_is_zero(point)) - return false; - - /* x and y must be smaller than p. */ - if (_vli_cmp(curve->p, point->x, ndigits) != 1 || - _vli_cmp(curve->p, point->y, ndigits) != 1) - return false; - - /* Computes result = y^2. */ - _vli_mod_square_fast(tmp1, point->y, curve->p, ndigits); - - /* Computes result = x^3 + ax + b. result must not overlap x. */ - /* r = x^2 */ - _vli_mod_square_fast(tmp2, point->x, curve->p, ndigits); - /* r = x^2 - 3 */ - _vli_mod_sub(tmp2, tmp2, _3, curve->p, ndigits); - /* r = x^3 - 3x */ - _vli_mod_mult_fast(tmp2, tmp2, point->x, curve->p, ndigits); - /* r = x^3 - 3x + b */ - _vli_mod_add(tmp2, tmp2, curve->b, curve->p, ndigits); - /* Make sure that y^2 == x^3 + ax + b */ - return (_vli_cmp(tmp1, tmp2, ndigits) == 0); -} - -void _ecc_be2native(uint64_t *dest, const uint64_t *bytes, - unsigned int ndigits) -{ - unsigned int i; - uint64_t tmp[L_ECC_MAX_DIGITS]; - - for (i = 0; i < ndigits; i++) - tmp[ndigits - 1 - i] = l_get_be64(&bytes[i]); - - memcpy(dest, tmp, ndigits * 8); -} - -void _ecc_native2be(uint64_t *dest, const uint64_t *native, - unsigned int ndigits) -{ - unsigned int i; - uint64_t tmp[L_ECC_MAX_DIGITS]; - - for (i = 0; i < ndigits; i++) - l_put_be64(native[ndigits - 1 - i], &tmp[i]); - - memcpy(dest, tmp, ndigits * 8); -} - -static void ecc_compute_y_sqr(const struct l_ecc_curve *curve, - uint64_t *y_sqr, const uint64_t *x) -{ - uint64_t sum[L_ECC_MAX_DIGITS] = { 0 }; - uint64_t tmp[L_ECC_MAX_DIGITS] = { 0 }; - uint64_t _3[L_ECC_MAX_DIGITS] = { 3ull }; /* -a = 3 */ - - /* x^3 */ - _vli_mod_square_fast(sum, x, curve->p, curve->ndigits); - _vli_mod_mult_fast(sum, sum, x, curve->p, curve->ndigits); - /* x^3 - ax */ - _vli_mod_mult_fast(tmp, _3, x, curve->p, curve->ndigits); - _vli_mod_sub(sum, sum, tmp, curve->p, curve->ndigits); - /* x^3 - ax + b */ - _vli_mod_add(sum, sum, curve->b, curve->p, curve->ndigits); - - memcpy(y_sqr, sum, curve->ndigits * 8); -} - -bool _ecc_compute_y(const struct l_ecc_curve *curve, uint64_t *y, uint64_t *x) -{ - /* - * y = sqrt(x^3 + ax + b) (mod p) - * - * Since our prime p satisfies p = 3 (mod 4), we can say: - * - * y = (x^3 - 3x + b)^((p + 1) / 4) - * - * This avoids the need for a square root function. - */ - - uint64_t sum[L_ECC_MAX_DIGITS] = { 0 }; - uint64_t expo[L_ECC_MAX_DIGITS] = { 0 }; - uint64_t one[L_ECC_MAX_DIGITS] = { 1ull }; - uint64_t check[L_ECC_MAX_DIGITS] = { 0 }; - - memcpy(expo, curve->p, curve->ndigits * 8); - - /* x^3 - 3x + b */ - ecc_compute_y_sqr(curve, sum, x); - - /* (p + 1) / 4 == (p >> 2) + 1 */ - _vli_rshift1(expo, curve->ndigits); - _vli_rshift1(expo, curve->ndigits); - _vli_mod_add(expo, expo, one, curve->p, curve->ndigits); - /* sum ^ ((p + 1) / 4) */ - _vli_mod_exp(y, sum, expo, curve->p, curve->ndigits); - - /* square y to ensure we have a correct value */ - _vli_mod_mult_fast(check, y, y, curve->p, curve->ndigits); - - if (_vli_cmp(check, sum, curve->ndigits) != 0) - return false; - - return true; -} - -/* - * IETF - Compact representation of an elliptic curve point: - * https://tools.ietf.org/id/draft-jivsov-ecc-compact-00.xml - * - * "min(y,p-y) can be calculated with the help of the pre-calculated value - * p2=(p-1)/2. min(y,p-y) is y if yp, one, curve->p, curve->ndigits); - _vli_rshift1(p2, curve->ndigits); -} - -/* - * IETF draft-jivsov-ecc-compact-00 Section 4.1 - * Encoding and decoding of an elliptic curve point - * ... - * Decoding: - * Given the compact representation of Q, return canonical representation - * of Q=(x,y) as follows: - * 1. y' = sqrt( x^3 + a*x + b ), where y'>0 - * 2. y = min(y',p-y') - * 3. Q=(x,y) is the canonical representation of the point - */ -static bool decode_point(const struct l_ecc_curve *curve, uint64_t *x, - struct l_ecc_point *point) -{ - uint64_t y_min[L_ECC_MAX_DIGITS]; - uint64_t p2[L_ECC_MAX_DIGITS]; - - if (!_ecc_compute_y(curve, y_min, (uint64_t *)x)) - return false; - - _ecc_calculate_p2(curve, p2); - - if (_vli_cmp(y_min, p2, curve->ndigits) >= 0) - _vli_mod_sub(point->y, curve->p, y_min, - curve->p, curve->ndigits); - else - memcpy(point->y, y_min, curve->ndigits * 8); - - memcpy(point->x, x, curve->ndigits * 8); - - return true; -} - -/* (rx, ry) = (px, py) + (qx, qy) */ -void _ecc_point_add(struct l_ecc_point *ret, const struct l_ecc_point *p, - const struct l_ecc_point *q, - const uint64_t *curve_prime) -{ - /* - * s = (py - qy)/(px - qx) - * - * rx = s^2 - px - qx - * ry = s(px - rx) - py - */ - uint64_t s[L_ECC_MAX_DIGITS]; - uint64_t kp1[L_ECC_MAX_DIGITS]; - uint64_t kp2[L_ECC_MAX_DIGITS]; - uint64_t resx[L_ECC_MAX_DIGITS]; - uint64_t resy[L_ECC_MAX_DIGITS]; - unsigned int ndigits = p->curve->ndigits; - - memset(s, 0, ndigits * 8); - - /* kp1 = py - qy */ - _vli_mod_sub(kp1, q->y, p->y, curve_prime, ndigits); - /* kp2 = px - qx */ - _vli_mod_sub(kp2, q->x, p->x, curve_prime, ndigits); - /* s = kp1/kp2 */ - _vli_mod_inv(kp2, kp2, curve_prime, ndigits); - _vli_mod_mult_fast(s, kp1, kp2, curve_prime, ndigits); - /* rx = s^2 - px - qx */ - _vli_mod_mult_fast(kp1, s, s, curve_prime, ndigits); - _vli_mod_sub(kp1, kp1, p->x, curve_prime, ndigits); - _vli_mod_sub(resx, kp1, q->x, curve_prime, ndigits); - /* ry = s(px - rx) - py */ - _vli_mod_sub(kp1, p->x, resx, curve_prime, ndigits); - _vli_mod_mult_fast(kp1, s, kp1, curve_prime, ndigits); - _vli_mod_sub(resy, kp1, p->y, curve_prime, ndigits); - - memcpy(ret->x, resx, ndigits * 8); - memcpy(ret->y, resy, ndigits * 8); -} - -/* result = (base ^ exp) % p */ -void _vli_mod_exp(uint64_t *result, uint64_t *base, uint64_t *exp, - const uint64_t *mod, unsigned int ndigits) -{ - unsigned int i; - int bit; - uint64_t n[L_ECC_MAX_DIGITS]; - uint64_t r[L_ECC_MAX_DIGITS] = { 1 }; - - memcpy(n, base, ndigits * 8); - - for (i = 0; i < ndigits; i++) { - for (bit = 0; bit < 64; bit++) { - uint64_t tmp[L_ECC_MAX_DIGITS]; - - if (exp[i] & (1ull << bit)) { - _vli_mod_mult_fast(tmp, r, n, mod, ndigits); - memcpy(r, tmp, ndigits * 8); - } - - _vli_mod_mult_fast(tmp, n, n, mod, ndigits); - memcpy(n, tmp, ndigits * 8); - } - } - - memcpy(result, r, ndigits * 8); -} - -int _vli_legendre(uint64_t *val, const uint64_t *p, unsigned int ndigits) -{ - uint64_t tmp[L_ECC_MAX_DIGITS]; - uint64_t exp[L_ECC_MAX_DIGITS]; - uint64_t _1[L_ECC_MAX_DIGITS] = { 1ull }; - uint64_t _0[L_ECC_MAX_DIGITS] = { 0 }; - - /* check that val ^ ((p - 1) / 2) == [1, 0 or -1] */ - - _vli_sub(exp, p, _1, ndigits); - _vli_rshift1(exp, ndigits); - _vli_mod_exp(tmp, val, exp, p, ndigits); - - if (_vli_cmp(tmp, _1, ndigits) == 0) - return 1; - else if (_vli_cmp(tmp, _0, ndigits) == 0) - return 0; - else - return -1; -} - -static bool vli_is_zero_or_one(const uint64_t *vli, unsigned int ndigits) -{ - unsigned int i; - - if (ndigits == 0 || vli[0] > 1) - return false; - - for (i = 1; i < ndigits; i++) { - if (vli[i]) - return false; - } - - return true; -} - -LIB_EXPORT struct l_ecc_point *l_ecc_point_new(const struct l_ecc_curve *curve) -{ - struct l_ecc_point *p = l_new(struct l_ecc_point, 1); - - p->curve = curve; - - return p; -} - -LIB_EXPORT struct l_ecc_point *l_ecc_point_from_data( - const struct l_ecc_curve *curve, - enum l_ecc_point_type type, - const void *data, size_t len) -{ - struct l_ecc_point *p; - size_t bytes = curve->ndigits * 8; - - if (!data) - return NULL; - - /* In all cases there should be an X coordinate in data */ - if (len < bytes) - return NULL; - - p = l_ecc_point_new(curve); - - _ecc_be2native(p->x, (void *) data, curve->ndigits); - - switch (type) { - case L_ECC_POINT_TYPE_COMPLIANT: - if (!decode_point(curve, p->x, p)) - goto failed; - - break; - case L_ECC_POINT_TYPE_COMPRESSED_BIT0: - if (!_ecc_compute_y(curve, p->y, p->x)) - goto failed; - - if (!(p->y[0] & 1)) - _vli_mod_sub(p->y, curve->p, p->y, curve->p, - curve->ndigits); - break; - case L_ECC_POINT_TYPE_COMPRESSED_BIT1: - if (!_ecc_compute_y(curve, p->y, p->x)) - goto failed; - - if (p->y[0] & 1) - _vli_mod_sub(p->y, curve->p, p->y, curve->p, - curve->ndigits); - - break; - case L_ECC_POINT_TYPE_FULL: - if (len < bytes * 2) - goto failed; - - _ecc_be2native(p->y, (void *) data + bytes, curve->ndigits); - - if (!ecc_valid_point(p)) - goto failed; - - break; - } - - return p; - -failed: - l_free(p); - return NULL; -} - -LIB_EXPORT ssize_t l_ecc_point_get_x(const struct l_ecc_point *p, void *x, - size_t xlen) -{ - if (xlen < p->curve->ndigits * 8) - return -EMSGSIZE; - - _ecc_native2be(x, (uint64_t *) p->x, p->curve->ndigits); - - return p->curve->ndigits * 8; -} - -LIB_EXPORT ssize_t l_ecc_point_get_data(const struct l_ecc_point *p, void *buf, - size_t len) -{ - if (len < (p->curve->ndigits * 8) * 2) - return -EMSGSIZE; - - _ecc_native2be(buf, (uint64_t *) p->x, p->curve->ndigits); - _ecc_native2be(buf + (p->curve->ndigits * 8), (uint64_t *) p->y, - p->curve->ndigits); - - return (p->curve->ndigits * 8) * 2; -} - -LIB_EXPORT void l_ecc_point_free(struct l_ecc_point *p) -{ - if (unlikely(!p)) - return; - - explicit_bzero(p->x, p->curve->ndigits * 8); - explicit_bzero(p->y, p->curve->ndigits * 8); - l_free(p); -} - -struct l_ecc_scalar *_ecc_constant_new(const struct l_ecc_curve *curve, - const void *buf, size_t len) -{ - struct l_ecc_scalar *c; - - if (unlikely(!curve)) - return NULL; - - if (buf && len != curve->ndigits * 8) - return NULL; - - c = l_new(struct l_ecc_scalar, 1); - - c->curve = curve; - - if (buf) - memcpy(c->c, buf, len); - - return c; -} - -LIB_EXPORT struct l_ecc_scalar *l_ecc_scalar_new( - const struct l_ecc_curve *curve, - const void *buf, size_t len) -{ - struct l_ecc_scalar *c; - - c = _ecc_constant_new(curve, NULL, 0); - if (!c) - return NULL; - - if (!buf) - return c; - - _ecc_be2native(c->c, buf, curve->ndigits); - - if (!vli_is_zero_or_one(c->c, curve->ndigits) && - _vli_cmp(c->c, curve->n, curve->ndigits) < 0) - return c; - - l_ecc_scalar_free(c); - - return NULL; -} - -LIB_EXPORT struct l_ecc_scalar *l_ecc_scalar_new_random( - const struct l_ecc_curve *curve) -{ - uint64_t r[L_ECC_MAX_DIGITS]; - - l_getrandom(r, curve->ndigits * 8); - - while (_vli_cmp(r, curve->p, curve->ndigits) > 0 || - _vli_cmp(r, curve->n, curve->ndigits) > 0 || - vli_is_zero_or_one(r, curve->ndigits)) - l_getrandom(r, curve->ndigits * 8); - - return _ecc_constant_new(curve, r, curve->ndigits * 8); -} - -LIB_EXPORT ssize_t l_ecc_scalar_get_data(const struct l_ecc_scalar *c, - void *buf, size_t len) -{ - if (len < c->curve->ndigits * 8) - return -EMSGSIZE; - - _ecc_native2be(buf, (uint64_t *) c->c, c->curve->ndigits); - - return c->curve->ndigits * 8; -} - -LIB_EXPORT void l_ecc_scalar_free(struct l_ecc_scalar *c) -{ - if (unlikely(!c)) - return; - - explicit_bzero(c->c, c->curve->ndigits * 8); - l_free(c); -} - -LIB_EXPORT struct l_ecc_scalar *l_ecc_curve_get_order( - const struct l_ecc_curve *curve) -{ - return _ecc_constant_new(curve, curve->n, curve->ndigits * 8); -} - -LIB_EXPORT bool l_ecc_scalar_add(struct l_ecc_scalar *ret, - const struct l_ecc_scalar *a, - const struct l_ecc_scalar *b, - const struct l_ecc_scalar *mod) -{ - if (unlikely(!ret || !a || !b || !mod)) - return false; - - _vli_mod_add(ret->c, a->c, b->c, mod->c, a->curve->ndigits); - - return true; -} - -LIB_EXPORT bool l_ecc_point_multiply(struct l_ecc_point *ret, - const struct l_ecc_scalar *scalar, - const struct l_ecc_point *point) -{ - if (unlikely(!ret || !scalar || !point)) - return false; - - _ecc_point_mult(ret, point, scalar->c, NULL, scalar->curve->p); - - return true; -} - -LIB_EXPORT bool l_ecc_point_add(struct l_ecc_point *ret, - const struct l_ecc_point *a, - const struct l_ecc_point *b) -{ - if (unlikely(!ret || !a || !b)) - return false; - - _ecc_point_add(ret, a, b, a->curve->p); - - return true; -} - -LIB_EXPORT bool l_ecc_point_inverse(struct l_ecc_point *p) -{ - if (unlikely(!p)) - return false; - - _vli_mod_sub(p->y, p->curve->p, p->y, p->curve->p, p->curve->ndigits); - - return true; -} - -LIB_EXPORT bool l_ecc_scalar_multiply(struct l_ecc_scalar *ret, - const struct l_ecc_scalar *a, - const struct l_ecc_scalar *b) -{ - if (unlikely(!ret || !a || !b)) - return false; - - _vli_mod_mult_fast(ret->c, a->c, b->c, a->curve->p, a->curve->ndigits); - - return true; -} - -LIB_EXPORT int l_ecc_scalar_legendre(struct l_ecc_scalar *value) -{ - if (unlikely(!value)) - return -1; - - return _vli_legendre(value->c, value->curve->p, value->curve->ndigits); -} - -LIB_EXPORT bool l_ecc_scalar_sum_x(struct l_ecc_scalar *ret, - const struct l_ecc_scalar *x) -{ - if (unlikely(!ret || !x)) - return false; - - ecc_compute_y_sqr(x->curve, ret->c, x->c); - - return true; -} - -LIB_EXPORT struct l_ecc_scalar *l_ecc_curve_get_prime( - const struct l_ecc_curve *curve) -{ - if (unlikely(!curve)) - return NULL; - - return _ecc_constant_new(curve, curve->p, curve->ndigits * 8); -} - -LIB_EXPORT bool l_ecc_scalars_are_equal(const struct l_ecc_scalar *a, - const struct l_ecc_scalar *b) -{ - if (unlikely(!a || !b)) - return false; - - return (memcmp(a->c, b->c, a->curve->ndigits * 8) == 0); -} - -LIB_EXPORT bool l_ecc_points_are_equal(const struct l_ecc_point *a, - const struct l_ecc_point *b) -{ - if (unlikely(!a || !b)) - return false; - - return ((memcmp(a->x, b->x, a->curve->ndigits * 8) == 0) && - (memcmp(a->y, b->y, a->curve->ndigits * 8) == 0)); -} diff --git a/ell/ecc.h b/ell/ecc.h deleted file mode 100644 index 26a5889..0000000 --- a/ell/ecc.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_ECC_H -#define __ELL_ECC_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define L_ECC_MAX_DIGITS 6 -#define L_ECC_SCALAR_MAX_BYTES L_ECC_MAX_DIGITS * 8 -#define L_ECC_POINT_MAX_BYTES L_ECC_SCALAR_MAX_BYTES * 2 - -struct l_ecc_curve; -struct l_ecc_point; -struct l_ecc_scalar; - -enum l_ecc_point_type { - L_ECC_POINT_TYPE_COMPLIANT = 0x01, - L_ECC_POINT_TYPE_COMPRESSED_BIT0 = 0x02, - L_ECC_POINT_TYPE_COMPRESSED_BIT1 = 0x03, - L_ECC_POINT_TYPE_FULL = 0x04, -}; - -const struct l_ecc_curve *l_ecc_curve_get(const char *name); -const char *l_ecc_curve_get_name(const struct l_ecc_curve *curve); -size_t l_ecc_curve_get_scalar_bytes(const struct l_ecc_curve *curve); -const unsigned int *l_ecc_curve_get_supported_ike_groups(void); -const unsigned int *l_ecc_curve_get_supported_tls_groups(void); -const struct l_ecc_curve *l_ecc_curve_get_ike_group(unsigned int group); -const struct l_ecc_curve *l_ecc_curve_get_tls_group(unsigned int group); - -struct l_ecc_point *l_ecc_point_new(const struct l_ecc_curve *curve); -struct l_ecc_point *l_ecc_point_from_data(const struct l_ecc_curve *curve, - enum l_ecc_point_type type, - const void *data, size_t len); - -ssize_t l_ecc_point_get_x(const struct l_ecc_point *p, void *x, size_t xlen); -ssize_t l_ecc_point_get_data(const struct l_ecc_point *p, void *buf, size_t len); -void l_ecc_point_free(struct l_ecc_point *p); - -struct l_ecc_scalar *l_ecc_scalar_new(const struct l_ecc_curve *curve, - const void *buf, size_t len); -struct l_ecc_scalar *l_ecc_scalar_new_random( - const struct l_ecc_curve *curve); -ssize_t l_ecc_scalar_get_data(const struct l_ecc_scalar *c, void *buf, - size_t len); -void l_ecc_scalar_free(struct l_ecc_scalar *c); - -/* Constant operations */ -struct l_ecc_scalar *l_ecc_curve_get_order(const struct l_ecc_curve *curve); -bool l_ecc_scalar_add(struct l_ecc_scalar *ret, const struct l_ecc_scalar *a, - const struct l_ecc_scalar *b, - const struct l_ecc_scalar *mod); - -/* Point operations */ -bool l_ecc_point_multiply(struct l_ecc_point *ret, - const struct l_ecc_scalar *scalar, - const struct l_ecc_point *point); -bool l_ecc_point_add(struct l_ecc_point *ret, const struct l_ecc_point *a, - const struct l_ecc_point *b); -bool l_ecc_point_inverse(struct l_ecc_point *p); - -/* extra operations needed for SAE */ -bool l_ecc_scalar_multiply(struct l_ecc_scalar *ret, - const struct l_ecc_scalar *a, - const struct l_ecc_scalar *b); -int l_ecc_scalar_legendre(struct l_ecc_scalar *value); -bool l_ecc_scalar_sum_x(struct l_ecc_scalar *ret, const struct l_ecc_scalar *x); - -struct l_ecc_scalar *l_ecc_curve_get_prime(const struct l_ecc_curve *curve); - -bool l_ecc_scalars_are_equal(const struct l_ecc_scalar *a, - const struct l_ecc_scalar *b); - -bool l_ecc_points_are_equal(const struct l_ecc_point *a, - const struct l_ecc_point *b); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_ECC_H */ diff --git a/ell/ecdh.c b/ell/ecdh.c deleted file mode 100644 index a10189f..0000000 --- a/ell/ecdh.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "private.h" -#include "ecc-private.h" -#include "ecc.h" -#include "ecdh.h" -#include "random.h" - -/* - * Some sane maximum for calculating the public key. - */ -#define ECDH_MAX_ITERATIONS 20 - -/* - * IETF draft-jivsov-ecc-compact-00 Section 4.2.1 - * - * The following algorithm calculates a key pair {k, Q=k*G=(x,y)}, where k is - * the private key and Q=(x,y) is the public key. - * - * Black box generation: - * 1. Generate a key pair {k, Q=k*G=(x,y)} with KG - * 2. if( y != min(y,p-y) ) goto step 1 - * 3. output {k, Q=(x,y)} as a key pair - */ -LIB_EXPORT bool l_ecdh_generate_key_pair(const struct l_ecc_curve *curve, - struct l_ecc_scalar **out_private, - struct l_ecc_point **out_public) -{ - bool compliant = false; - int iter = 0; - uint64_t p2[L_ECC_MAX_DIGITS]; - - _ecc_calculate_p2(curve, p2); - - *out_public = l_ecc_point_new(curve); - - while (!compliant && iter++ < ECDH_MAX_ITERATIONS) { - *out_private = l_ecc_scalar_new_random(curve); - - _ecc_point_mult(*out_public, &curve->g, (*out_private)->c, - NULL, curve->p); - - /* ensure public key is compliant */ - if (_vli_cmp((*out_public)->y, p2, curve->ndigits) >= 0) { - compliant = true; - break; - } - - l_ecc_scalar_free(*out_private); - } - - if (!compliant) { - l_ecc_point_free(*out_public); - return false; - } - - return true; -} - -LIB_EXPORT bool l_ecdh_generate_shared_secret( - const struct l_ecc_scalar *private_key, - const struct l_ecc_point *other_public, - struct l_ecc_scalar **secret) -{ - const struct l_ecc_curve *curve = private_key->curve; - struct l_ecc_scalar *z; - struct l_ecc_point *product; - - z = l_ecc_scalar_new_random(curve); - - product = l_ecc_point_new(curve); - - _ecc_point_mult(product, other_public, private_key->c, z->c, curve->p); - - *secret = _ecc_constant_new(curve, product->x, curve->ndigits * 8); - - l_ecc_point_free(product); - l_ecc_scalar_free(z); - - return true; -} diff --git a/ell/ecdh.h b/ell/ecdh.h deleted file mode 100644 index 34cbc6b..0000000 --- a/ell/ecdh.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_ECDH_H -#define __ELL_ECDH_H - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_ecc_curve; -struct l_ecc_point; -struct l_ecc_scalar; - -/* - * Generate a private/public key pair. private/public are out parameters and - * must be freed. - */ -bool l_ecdh_generate_key_pair(const struct l_ecc_curve *curve, - struct l_ecc_scalar **out_private, - struct l_ecc_point **out_public); -/* - * Generate a shared secret from a private/public key. secret is an out - * parameters and must be freed. - */ -bool l_ecdh_generate_shared_secret(const struct l_ecc_scalar *private_key, - const struct l_ecc_point *other_public, - struct l_ecc_scalar **secret); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_ECDH_H */ diff --git a/ell/ell.h b/ell/ell.h deleted file mode 100644 index 3bb9185..0000000 --- a/ell/ell.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include diff --git a/ell/file.c b/ell/file.c deleted file mode 100644 index 2d04452..0000000 --- a/ell/file.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2017 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include -#include -#include -#include -#include - -#include "file.h" -#include "private.h" - -/** - * l_file_get_contents: - * @filename: File to load - * @out_len: Set to the length of the loaded file - * - * Attempts to load the contents of a file via sequential read system calls. - * This can be useful for files that are not mmapable, e.g. sysfs entries. - * - * Returns: A newly allocated memory region with the file contents - **/ -LIB_EXPORT void *l_file_get_contents(const char *filename, size_t *out_len) -{ - int fd; - struct stat st; - uint8_t *contents; - size_t bytes_read = 0; - ssize_t nread; - - fd = open(filename, O_RDONLY); - if (fd < 0) - return NULL; - - if (fstat(fd, &st) < 0) { - close(fd); - return NULL; - } - - contents = l_malloc(st.st_size); - - do { - nread = read(fd, contents + bytes_read, 4096); - - if (nread < 0) { - if (errno == EINTR) - continue; - - goto error; - } - - bytes_read += nread; - } while (nread != 0); - - if (out_len) - *out_len = bytes_read; - - close(fd); - return contents; - -error: - l_free(contents); - close(fd); - return NULL; -} diff --git a/ell/file.h b/ell/file.h deleted file mode 100644 index 4ae37dd..0000000 --- a/ell/file.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2017 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_FILE_H -#define __ELL_FILE_H - -#ifdef __cplusplus -extern "C" { -#endif - -void *l_file_get_contents(const char *filename, size_t *out_len); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_FILE_H */ diff --git a/ell/genl-private.h b/ell/genl-private.h deleted file mode 100644 index 3c3e525..0000000 --- a/ell/genl-private.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2015 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -struct l_genl_msg *_genl_msg_create(const struct nlmsghdr *nlmsg); -const void *_genl_msg_as_bytes(struct l_genl_msg *msg, uint16_t type, - uint16_t flags, uint32_t seq, - uint32_t pid, - size_t *out_size); diff --git a/ell/genl.c b/ell/genl.c deleted file mode 100644 index 431ed05..0000000 --- a/ell/genl.c +++ /dev/null @@ -1,2062 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "util.h" -#include "queue.h" -#include "io.h" -#include "netlink-private.h" -#include "genl.h" -#include "genl-private.h" -#include "private.h" - -#define MAX_NESTING_LEVEL 4 -#define GENL_DEBUG(fmt, args...) \ - l_util_debug(genl->debug_callback, genl->debug_data, "%s:%i " fmt, \ - __func__, __LINE__, ## args) - -struct nest_info { - uint16_t type; - uint16_t offset; -}; - -struct unicast_watch { - uint32_t id; - char name[GENL_NAMSIZ]; - l_genl_msg_func_t handler; - void *user_data; - l_genl_destroy_func_t destroy; -}; - -struct family_watch { - uint32_t id; - char *name; - l_genl_discover_func_t appeared_func; - l_genl_vanished_func_t vanished_func; - l_genl_destroy_func_t destroy; - void *user_data; -}; - -struct genl_discovery { - l_genl_discover_func_t cb; - l_genl_destroy_func_t destroy; - void *user_data; - uint32_t cmd_id; -}; - -struct l_genl { - int ref_count; - int fd; - uint32_t pid; - uint32_t next_seq; - struct l_io *io; - struct l_queue *request_queue; - struct l_queue *pending_list; - struct l_queue *notify_list; - unsigned int next_request_id; - unsigned int next_notify_id; - struct genl_discovery *discovery; - uint32_t next_watch_id; - struct l_queue *unicast_watches; - struct l_queue *family_watches; - struct l_queue *family_infos; - struct l_genl_family *nlctrl; - uint32_t next_handle_id; - l_genl_debug_func_t debug_callback; - l_genl_destroy_func_t debug_destroy; - void *debug_data; - - bool in_family_watch_notify : 1; - bool in_unicast_watch_notify : 1; - bool in_mcast_notify : 1; - bool writer_active : 1; -}; - -struct l_genl_msg { - int ref_count; - int error; - uint8_t cmd; - uint8_t version; - void *data; - uint32_t size; - uint32_t len; - struct nest_info nests[MAX_NESTING_LEVEL]; - uint8_t nesting_level; -}; - -struct genl_request { - unsigned int id; - uint32_t handle_id; - uint16_t type; - uint16_t flags; - uint32_t seq; - struct l_genl_msg *msg; - l_genl_msg_func_t callback; - l_genl_destroy_func_t destroy; - void *user_data; -}; - -struct mcast_notify { - unsigned int id; - uint32_t handle_id; - uint16_t type; - uint32_t group; - l_genl_msg_func_t callback; - l_genl_destroy_func_t destroy; - void *user_data; -}; - -struct genl_op { - uint32_t id; - uint32_t flags; -}; - -struct genl_mcast { - char name[GENL_NAMSIZ]; - uint32_t id; - unsigned int users; -}; - -struct l_genl_family_info { - char name[GENL_NAMSIZ]; - uint16_t id; - uint32_t version; - uint32_t hdrsize; - uint32_t maxattr; - struct l_queue *op_list; - struct l_queue *mcast_list; -}; - -struct l_genl_family { - uint16_t id; - uint32_t handle_id; - struct l_genl *genl; -}; - -static inline uint32_t get_next_id(uint32_t *id) -{ - *id += 1; - if (!*id) - *id = 1; - - return *id; -} - -static bool family_info_match(const void *a, const void *b) -{ - const struct l_genl_family_info *ia = a; - uint16_t id = L_PTR_TO_UINT(b); - - return ia->id == id; -} - -static struct l_genl_family_info *family_info_new(const char *name) -{ - struct l_genl_family_info *info = l_new(struct l_genl_family_info, 1); - - l_strlcpy(info->name, name, GENL_NAMSIZ); - info->op_list = l_queue_new(); - info->mcast_list = l_queue_new(); - return info; -} - -static void family_info_free(void *user_data) -{ - struct l_genl_family_info *info = user_data; - - l_queue_destroy(info->op_list, l_free); - info->op_list = NULL; - l_queue_destroy(info->mcast_list, l_free); - info->mcast_list = NULL; - l_free(info); -} - -static void family_info_add_op(struct l_genl_family_info *info, - uint32_t id, uint32_t flags) -{ - struct genl_op *op; - - op = l_new(struct genl_op, 1); - - op->id = id; - op->flags = flags; - - l_queue_push_tail(info->op_list, op); -} - -static bool match_mcast_name(const void *a, const void *b) -{ - const struct genl_mcast *mcast = a; - const char *name = b; - - return !strncmp(mcast->name, name, GENL_NAMSIZ); -} - -static bool match_mcast_id(const void *a, const void *b) -{ - const struct genl_mcast *mcast = a; - uint32_t id = L_PTR_TO_UINT(b); - - return mcast->id == id; -} - -static void family_info_add_mcast(struct l_genl_family_info *info, - const char *name, uint32_t id) -{ - struct genl_mcast *mcast; - - mcast = l_queue_find(info->mcast_list, match_mcast_name, name); - if (mcast) - return; - - mcast = l_new(struct genl_mcast, 1); - l_strlcpy(mcast->name, name, GENL_NAMSIZ); - mcast->id = id; - mcast->users = 0; - - l_queue_push_tail(info->mcast_list, mcast); -} - -static void family_ops(struct l_genl_family_info *info, - struct l_genl_attr *attr) -{ - uint16_t type, len; - const void *data; - - while (l_genl_attr_next(attr, &type, &len, &data)) { - struct l_genl_attr attr_op; - uint32_t id = 0, flags = 0; - - l_genl_attr_recurse(attr, &attr_op); - - while (l_genl_attr_next(&attr_op, &type, &len, &data)) { - switch (type) { - case CTRL_ATTR_OP_ID: - id = *((uint32_t *) data); - break; - case CTRL_ATTR_OP_FLAGS: - flags = *((uint32_t *) data); - break; - } - } - - if (id > 0) - family_info_add_op(info, id, flags); - } -} - -static void family_mcast_groups(struct l_genl_family_info *info, - struct l_genl_attr *attr) -{ - uint16_t type, len; - const void *data; - - while (l_genl_attr_next(attr, &type, &len, &data)) { - struct l_genl_attr attr_grp; - const char *name = NULL; - uint32_t id = 0; - - l_genl_attr_recurse(attr, &attr_grp); - - while (l_genl_attr_next(&attr_grp, &type, &len, &data)) { - switch (type) { - case CTRL_ATTR_MCAST_GRP_NAME: - name = data; - break; - case CTRL_ATTR_MCAST_GRP_ID: - id = *((uint32_t *) data); - break; - } - } - - if (name && id > 0) - family_info_add_mcast(info, name, id); - } -} - -static int parse_cmd_newfamily(struct l_genl_family_info *info, - struct l_genl_msg *msg) -{ - struct l_genl_attr attr, nested; - uint16_t type, len; - const void *data; - int error; - - error = l_genl_msg_get_error(msg); - if (error < 0) - return error; - - if (!l_genl_attr_init(&attr, msg)) - return -EINVAL; - - while (l_genl_attr_next(&attr, &type, &len, &data)) { - switch (type) { - case CTRL_ATTR_FAMILY_ID: - info->id = *((uint16_t *) data); - break; - case CTRL_ATTR_FAMILY_NAME: - l_strlcpy(info->name, data, GENL_NAMSIZ); - break; - case CTRL_ATTR_VERSION: - info->version = l_get_u32(data); - break; - case CTRL_ATTR_HDRSIZE: - info->hdrsize = l_get_u32(data); - break; - case CTRL_ATTR_MAXATTR: - info->maxattr = l_get_u32(data); - break; - case CTRL_ATTR_OPS: - if (l_genl_attr_recurse(&attr, &nested)) - family_ops(info, &nested); - break; - case CTRL_ATTR_MCAST_GROUPS: - if (l_genl_attr_recurse(&attr, &nested)) - family_mcast_groups(info, &nested); - break; - } - } - - return 0; -} - -LIB_EXPORT bool l_genl_family_info_has_group( - const struct l_genl_family_info *info, - const char *group) -{ - struct genl_mcast *mcast; - - if (unlikely(!info)) - return false; - - mcast = l_queue_find(info->mcast_list, match_mcast_name, - (char *) group); - if (!mcast) - return false; - - return true; -} - -static bool match_op_id(const void *a, const void *b) -{ - const struct genl_op *op = a; - uint32_t id = L_PTR_TO_UINT(b); - - return op->id == id; -} - -LIB_EXPORT bool l_genl_family_info_can_send( - const struct l_genl_family_info *info, - uint8_t cmd) -{ - struct genl_op *op; - - if (unlikely(!info)) - return false; - - op = l_queue_find(info->op_list, match_op_id, L_UINT_TO_PTR(cmd)); - if (!op) - return false; - - if (op->flags & GENL_CMD_CAP_DO) - return true; - - return false; -} - -LIB_EXPORT bool l_genl_family_info_can_dump( - const struct l_genl_family_info *info, - uint8_t cmd) -{ - struct genl_op *op; - - if (!info) - return false; - - op = l_queue_find(info->op_list, match_op_id, L_UINT_TO_PTR(cmd)); - if (!op) - return false; - - if (op->flags & GENL_CMD_CAP_DUMP) - return true; - - return false; -} - -LIB_EXPORT char **l_genl_family_info_get_groups( - const struct l_genl_family_info *info) -{ - char **groups; - size_t n_groups; - const struct l_queue_entry *entry; - int i; - - if (unlikely(!info)) - return NULL; - - n_groups = l_queue_length(info->mcast_list); - groups = l_new(char *, n_groups + 1); - - for (entry = l_queue_get_entries(info->mcast_list), i = 0; - entry; entry = entry->next) { - struct genl_mcast *mcast = entry->data; - - groups[i++] = l_strdup(mcast->name); - } - - return groups; -} - -LIB_EXPORT uint32_t l_genl_family_info_get_id( - const struct l_genl_family_info *info) -{ - if (unlikely(!info)) - return 0; - - return info->id; -} - -LIB_EXPORT const char *l_genl_family_info_get_name( - const struct l_genl_family_info *info) -{ - if (unlikely(!info)) - return NULL; - - return info->name; -} - -LIB_EXPORT uint32_t l_genl_family_info_get_version( - const struct l_genl_family_info *info) -{ - if (unlikely(!info)) - return 0; - - return info->version; -} - -static void unicast_watch_free(void *data) -{ - struct unicast_watch *watch = data; - - if (watch->destroy) - watch->destroy(watch->user_data); - - l_free(watch); -} - -static bool unicast_watch_match(const void *a, const void *b) -{ - const struct unicast_watch *watch = a; - uint32_t id = L_PTR_TO_UINT(b); - - return watch->id == id; -} - -static void unicast_watch_prune(struct l_genl *genl) -{ - struct unicast_watch *watch; - - while ((watch = l_queue_remove_if(genl->unicast_watches, - unicast_watch_match, - L_UINT_TO_PTR(0)))) - unicast_watch_free(watch); -} - -static void family_watch_free(void *data) -{ - struct family_watch *watch = data; - - if (watch->destroy) - watch->destroy(watch->user_data); - - l_free(watch->name); - l_free(watch); -} - -static bool family_watch_match(const void *a, const void *b) -{ - const struct family_watch *watch = a; - uint32_t id = L_PTR_TO_UINT(b); - - return watch->id == id; -} - -static struct l_genl_family_info *family_info_update(struct l_genl *genl, - struct l_genl_family_info *info) -{ - struct l_genl_family_info *old = - l_queue_find(genl->family_infos, family_info_match, - L_UINT_TO_PTR(info->id)); - if (old) { - GENL_DEBUG("Keeping old family info: %s", old->name); - family_info_free(info); - return old; - } - - GENL_DEBUG("Added new family info: %s", info->name); - l_queue_push_head(genl->family_infos, info); - return info; -} - -static void family_watch_prune(struct l_genl *genl) -{ - struct family_watch *watch; - - while ((watch = l_queue_remove_if(genl->family_watches, - family_watch_match, - L_UINT_TO_PTR(0)))) - family_watch_free(watch); -} - -static void nlctrl_newfamily(struct l_genl_msg *msg, struct l_genl *genl) -{ - struct l_genl_family_info *info = family_info_new(NULL); - const struct l_queue_entry *entry; - - if (parse_cmd_newfamily(info, msg) < 0) { - family_info_free(info); - return; - } - - info = family_info_update(genl, info); - - genl->in_family_watch_notify = true; - - for (entry = l_queue_get_entries(genl->family_watches); - entry; entry = entry->next) { - struct family_watch *watch = entry->data; - - if (!watch->id) - continue; - - if (!watch->appeared_func) - continue; - - if (watch->name && strcmp(watch->name, info->name)) - continue; - - watch->appeared_func(info, watch->user_data); - } - - genl->in_family_watch_notify = false; - family_watch_prune(genl); -} - -static void nlctrl_delfamily(struct l_genl_msg *msg, struct l_genl *genl) -{ - const struct l_queue_entry *entry; - struct l_genl_attr attr; - uint16_t type, len; - const void *data; - uint16_t id = 0; - const char *name = NULL; - struct l_genl_family_info *old; - - if (!l_genl_attr_init(&attr, msg)) - return; - - while (l_genl_attr_next(&attr, &type, &len, &data)) { - switch (type) { - case CTRL_ATTR_FAMILY_ID: - id = l_get_u16(data); - break; - case CTRL_ATTR_FAMILY_NAME: - name = data; - break; - } - } - - if (!id || !name) - return; - - genl->in_family_watch_notify = true; - - for (entry = l_queue_get_entries(genl->family_watches); - entry; entry = entry->next) { - struct family_watch *watch = entry->data; - - if (!watch->id) - continue; - - if (!watch->vanished_func) - continue; - - if (watch->name && strcmp(watch->name, name)) - continue; - - watch->vanished_func(name, watch->user_data); - } - - genl->in_family_watch_notify = false; - family_watch_prune(genl); - - old = l_queue_remove_if(genl->family_infos, family_info_match, - L_UINT_TO_PTR(id)); - if (old) { - GENL_DEBUG("Removing old family info: %s", old->name); - family_info_free(old); - } -} - -static void nlctrl_notify(struct l_genl_msg *msg, void *user_data) -{ - struct l_genl *genl = user_data; - uint8_t cmd; - - cmd = l_genl_msg_get_command(msg); - - switch (cmd) { - case CTRL_CMD_NEWFAMILY: - nlctrl_newfamily(msg, genl); - break; - case CTRL_CMD_DELFAMILY: - nlctrl_delfamily(msg, genl); - break; - case CTRL_CMD_NEWOPS: - GENL_DEBUG("CMD_NEWOPS"); - break; - case CTRL_CMD_DELOPS: - GENL_DEBUG("CMD_DELOPS"); - break; - case CTRL_CMD_NEWMCAST_GRP: - GENL_DEBUG("CMD_NEWMCAST_GRP"); - break; - case CTRL_CMD_DELMCAST_GRP: - GENL_DEBUG("CMD_DELMCAST_GRP"); - break; - } -} - -static struct l_genl_family *family_alloc(struct l_genl *genl, uint16_t id) -{ - struct l_genl_family *family; - - family = l_new(struct l_genl_family, 1); - family->genl = genl; - family->id = id; - family->handle_id = get_next_id(&genl->next_handle_id); - return family; -} - -static void destroy_request(void *data) -{ - struct genl_request *request = data; - - if (request->destroy) - request->destroy(request->user_data); - - l_genl_msg_unref(request->msg); - - l_free(request); -} - -static void mcast_notify_free(void *data) -{ - struct mcast_notify *notify = data; - - if (notify->destroy) - notify->destroy(notify->user_data); - - l_free(notify); -} - -static bool mcast_notify_match(const void *a, const void *b) -{ - const struct mcast_notify *notify = a; - uint32_t id = L_PTR_TO_UINT(b); - - return notify->id == id; -} - -static bool mcast_notify_match_by_hid(const void *a, const void *b) -{ - const struct mcast_notify *notify = a; - uint32_t id = L_PTR_TO_UINT(b); - - return notify->handle_id == id; -} - -static void mcast_notify_prune(struct l_genl *genl) -{ - struct mcast_notify *notify; - - while ((notify = l_queue_remove_if(genl->notify_list, - mcast_notify_match, - L_UINT_TO_PTR(0)))) - mcast_notify_free(notify); -} - -static bool match_request_id(const void *a, const void *b) -{ - const struct genl_request *request = a; - unsigned int id = L_PTR_TO_UINT(b); - - return request->id == id; -} - -static bool match_request_hid(const void *a, const void *b) -{ - const struct genl_request *request = a; - unsigned int id = L_PTR_TO_UINT(b); - - return request->handle_id == id; -} - -static struct l_genl_msg *msg_alloc(uint8_t cmd, uint8_t version, uint32_t size) -{ - struct l_genl_msg *msg; - - msg = l_new(struct l_genl_msg, 1); - - msg->cmd = cmd; - msg->version = version; - - msg->len = NLMSG_HDRLEN + GENL_HDRLEN; - msg->size = msg->len + NLMSG_ALIGN(size); - - msg->data = l_realloc(NULL, msg->size); - memset(msg->data, 0, msg->size); - msg->nesting_level = 0; - - return l_genl_msg_ref(msg); -} - -static bool msg_grow(struct l_genl_msg *msg, uint32_t needed) -{ - uint32_t grow_by; - - if (msg->size >= msg->len + needed) - return true; - - grow_by = msg->len + needed - msg->size; - - if (grow_by < 32) - grow_by = 128; - - msg->data = l_realloc(msg->data, msg->size + grow_by); - memset(msg->data + msg->size, 0, grow_by); - msg->size += grow_by; - - return true; -} - -struct l_genl_msg *_genl_msg_create(const struct nlmsghdr *nlmsg) -{ - struct l_genl_msg *msg; - - msg = l_new(struct l_genl_msg, 1); - - if (nlmsg->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = NLMSG_DATA(nlmsg); - - msg->error = err->error; - goto done; - } - - msg->data = l_memdup(nlmsg, nlmsg->nlmsg_len); - - msg->len = nlmsg->nlmsg_len; - msg->size = nlmsg->nlmsg_len; - - if (msg->len >= GENL_HDRLEN) { - struct genlmsghdr *genlmsg = msg->data + NLMSG_HDRLEN; - - msg->cmd = genlmsg->cmd; - msg->version = genlmsg->version; - } - -done: - return l_genl_msg_ref(msg); -} - -static void write_watch_destroy(void *user_data) -{ - struct l_genl *genl = user_data; - - genl->writer_active = false; -} - -static bool can_write_data(struct l_io *io, void *user_data) -{ - struct l_genl *genl = user_data; - struct genl_request *request; - struct nlmsghdr *nlmsg; - struct genlmsghdr *genlmsg; - ssize_t bytes_written; - - request = l_queue_pop_head(genl->request_queue); - if (!request) - return false; - - request->seq = get_next_id(&genl->next_seq); - - nlmsg = request->msg->data; - - nlmsg->nlmsg_len = request->msg->len; - nlmsg->nlmsg_type = request->type; - nlmsg->nlmsg_flags = request->flags; - nlmsg->nlmsg_seq = request->seq; - nlmsg->nlmsg_pid = genl->pid; - - genlmsg = request->msg->data + NLMSG_HDRLEN; - - genlmsg->cmd = request->msg->cmd; - genlmsg->version = request->msg->version; - - bytes_written = send(genl->fd, request->msg->data, - request->msg->len, 0); - if (bytes_written < 0) { - l_queue_push_head(genl->request_queue, request); - return false; - } - - l_util_hexdump(false, request->msg->data, bytes_written, - genl->debug_callback, genl->debug_data); - - l_queue_push_tail(genl->pending_list, request); - - return false; -} - -static void wakeup_writer(struct l_genl *genl) -{ - if (genl->writer_active) - return; - - if (l_queue_isempty(genl->request_queue)) - return; - - if (!l_queue_isempty(genl->pending_list)) - return; - - l_io_set_write_handler(genl->io, can_write_data, genl, - write_watch_destroy); - - genl->writer_active = true; -} - -static bool match_request_seq(const void *a, const void *b) -{ - const struct genl_request *request = a; - uint32_t seq = L_PTR_TO_UINT(b); - - return request->seq == seq; -} - -static void dispatch_unicast_watches(struct l_genl *genl, uint16_t id, - struct l_genl_msg *msg) -{ - const struct l_queue_entry *entry; - struct l_genl_family_info *info = l_queue_find(genl->family_infos, - family_info_match, - L_UINT_TO_PTR(id)); - - if (!info) - return; - - genl->in_unicast_watch_notify = true; - - for (entry = l_queue_get_entries(genl->unicast_watches); - entry; entry = entry->next) { - struct unicast_watch *watch = entry->data; - - if (!watch->id) - continue; - - if (!watch->handler) - continue; - - if (strncmp(watch->name, info->name, GENL_NAMSIZ)) - continue; - - watch->handler(msg, watch->user_data); - } - - genl->in_unicast_watch_notify = false; - unicast_watch_prune(genl); -} - -static void process_unicast(struct l_genl *genl, const struct nlmsghdr *nlmsg) -{ - struct l_genl_msg *msg; - struct genl_request *request; - - if (nlmsg->nlmsg_type == NLMSG_NOOP || - nlmsg->nlmsg_type == NLMSG_OVERRUN) - return; - - msg = _genl_msg_create(nlmsg); - if (!nlmsg->nlmsg_seq) { - if (msg) - dispatch_unicast_watches(genl, nlmsg->nlmsg_type, msg); - goto done; - } - - request = l_queue_remove_if(genl->pending_list, match_request_seq, - L_UINT_TO_PTR(nlmsg->nlmsg_seq)); - if (!request) - goto done; - - if (!msg) - goto free_request; - - if (request->callback && nlmsg->nlmsg_type != NLMSG_DONE) - request->callback(msg, request->user_data); - - if ((nlmsg->nlmsg_flags & NLM_F_MULTI) && - nlmsg->nlmsg_type != NLMSG_DONE) { - l_queue_push_head(genl->pending_list, request); - goto done; - } - -free_request: - destroy_request(request); - wakeup_writer(genl); -done: - l_genl_msg_unref(msg); -} - -static void process_multicast(struct l_genl *genl, uint32_t group, - const struct nlmsghdr *nlmsg) -{ - const struct l_queue_entry *entry; - struct l_genl_msg *msg = _genl_msg_create(nlmsg); - - if (!msg) - return; - - genl->in_mcast_notify = true; - - for (entry = l_queue_get_entries(genl->notify_list); - entry; entry = entry->next) { - struct mcast_notify *notify = entry->data; - - if (notify->type != nlmsg->nlmsg_type) - continue; - - if (notify->group != group) - continue; - - if (!notify->callback) - continue; - - notify->callback(msg, notify->user_data); - } - - genl->in_mcast_notify = false; - mcast_notify_prune(genl); - - l_genl_msg_unref(msg); -} - -static void read_watch_destroy(void *user_data) -{ -} - -static bool received_data(struct l_io *io, void *user_data) -{ - struct l_genl *genl = user_data; - struct cmsghdr *cmsg; - struct msghdr msg; - struct iovec iov; - unsigned char buf[8192]; - unsigned char control[32]; - ssize_t bytes_read; - struct nlmsghdr *nlmsg; - size_t nlmsg_len; - uint32_t group = 0; - - memset(&iov, 0, sizeof(iov)); - iov.iov_base = buf; - iov.iov_len = sizeof(buf); - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = control; - msg.msg_controllen = sizeof(control); - - bytes_read = recvmsg(genl->fd, &msg, 0); - if (bytes_read < 0) { - if (errno != EAGAIN && errno != EINTR) - return false; - - return true; - } - - nlmsg_len = bytes_read; - - l_util_hexdump(true, buf, nlmsg_len, - genl->debug_callback, genl->debug_data); - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - struct nl_pktinfo pktinfo; - - if (cmsg->cmsg_level != SOL_NETLINK) - continue; - - if (cmsg->cmsg_type != NETLINK_PKTINFO) - continue; - - memcpy(&pktinfo, CMSG_DATA(cmsg), sizeof(pktinfo)); - - group = pktinfo.group; - } - - for (nlmsg = iov.iov_base; NLMSG_OK(nlmsg, nlmsg_len); - nlmsg = NLMSG_NEXT(nlmsg, nlmsg_len)) { - if (group > 0) - process_multicast(genl, group, nlmsg); - else - process_unicast(genl, nlmsg); - } - - return true; -} - -static struct l_genl_family_info *build_nlctrl_info() -{ - struct l_genl_family_info *r = family_info_new("nlctrl"); - - r->id = GENL_ID_CTRL; - family_info_add_mcast(r, "notify", GENL_ID_CTRL); - family_info_add_op(r, CTRL_CMD_GETFAMILY, GENL_CMD_CAP_DUMP); - - return r; -} - -LIB_EXPORT struct l_genl *l_genl_new(void) -{ - struct l_genl *genl; - struct sockaddr_nl addr; - socklen_t addrlen = sizeof(addr); - int fd, pktinfo = 1; - - fd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - NETLINK_GENERIC); - if (fd < 0) - return NULL; - - memset(&addr, 0, sizeof(addr)); - addr.nl_family = AF_NETLINK; - addr.nl_pid = 0; - - if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) - goto err; - - if (getsockname(fd, (struct sockaddr *) &addr, &addrlen) < 0) - goto err; - - if (setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, - &pktinfo, sizeof(pktinfo)) < 0) - goto err; - - genl = l_new(struct l_genl, 1); - genl->pid = addr.nl_pid; - genl->ref_count = 1; - genl->fd = fd; - genl->io = l_io_new(genl->fd); - l_io_set_read_handler(genl->io, received_data, genl, - read_watch_destroy); - - genl->request_queue = l_queue_new(); - genl->pending_list = l_queue_new(); - genl->notify_list = l_queue_new(); - genl->family_watches = l_queue_new(); - genl->family_infos = l_queue_new(); - genl->unicast_watches = l_queue_new(); - - l_queue_push_head(genl->family_infos, build_nlctrl_info()); - - genl->nlctrl = family_alloc(genl, GENL_ID_CTRL); - l_genl_family_register(genl->nlctrl, "notify", - nlctrl_notify, genl, NULL); - - return genl; - -err: - close(fd); - return NULL; -} - -LIB_EXPORT struct l_genl *l_genl_ref(struct l_genl *genl) -{ - if (unlikely(!genl)) - return NULL; - - __sync_fetch_and_add(&genl->ref_count, 1); - - return genl; -} - -LIB_EXPORT void l_genl_unref(struct l_genl *genl) -{ - if (unlikely(!genl)) - return; - - if (__sync_sub_and_fetch(&genl->ref_count, 1)) - return; - - if (genl->discovery) { - if (genl->discovery->destroy) - genl->discovery->destroy(genl->discovery->user_data); - - l_free(genl->discovery); - genl->discovery = NULL; - } - - l_genl_family_free(genl->nlctrl); - - l_queue_destroy(genl->unicast_watches, unicast_watch_free); - l_queue_destroy(genl->family_watches, family_watch_free); - l_queue_destroy(genl->family_infos, family_info_free); - l_queue_destroy(genl->notify_list, mcast_notify_free); - l_queue_destroy(genl->pending_list, destroy_request); - l_queue_destroy(genl->request_queue, destroy_request); - - l_io_set_write_handler(genl->io, NULL, NULL, NULL); - l_io_set_read_handler(genl->io, NULL, NULL, NULL); - - l_io_destroy(genl->io); - genl->io = NULL; - close(genl->fd); - - if (genl->debug_destroy) - genl->debug_destroy(genl->debug_data); - - l_free(genl); -} - -LIB_EXPORT bool l_genl_set_debug(struct l_genl *genl, - l_genl_debug_func_t callback, - void *user_data, - l_genl_destroy_func_t destroy) -{ - if (unlikely(!genl)) - return false; - - if (genl->debug_destroy) - genl->debug_destroy(genl->debug_data); - - genl->debug_callback = callback; - genl->debug_destroy = destroy; - genl->debug_data = user_data; - - return true; -} - -static void dump_family_callback(struct l_genl_msg *msg, void *user_data) -{ - struct l_genl *genl = user_data; - struct genl_discovery *discovery = genl->discovery; - struct l_genl_family_info *info = family_info_new(NULL); - - discovery->cmd_id = 0; - - if (parse_cmd_newfamily(info, msg) < 0) { - family_info_free(info); - return; - } - - info = family_info_update(genl, info); - - if (discovery->cb) - discovery->cb(info, discovery->user_data); -} - -static void dump_family_done(void *user_data) -{ - struct l_genl *genl = user_data; - struct genl_discovery *discovery = genl->discovery; - - if (discovery->destroy) - discovery->destroy(discovery->user_data); - - l_free(discovery); - genl->discovery = NULL; -} - -LIB_EXPORT bool l_genl_discover_families(struct l_genl *genl, - l_genl_discover_func_t cb, - void *user_data, - l_genl_destroy_func_t destroy) -{ - struct l_genl_msg *msg; - struct genl_discovery *discovery; - - if (unlikely(!genl)) - return false; - - if (genl->discovery) - return false; - - discovery = l_new(struct genl_discovery, 1); - discovery->cb = cb; - discovery->user_data = user_data; - discovery->destroy = destroy; - - msg = l_genl_msg_new_sized(CTRL_CMD_GETFAMILY, NLA_HDRLEN); - discovery->cmd_id = l_genl_family_dump(genl->nlctrl, msg, - dump_family_callback, - genl, dump_family_done); - - if (!discovery->cmd_id) { - l_free(discovery); - return false; - } - - genl->discovery = discovery; - return true; -} - -/** - * l_genl_add_unicast_watch: - * @genl: GENL connection - * @name: Name of the family for which a unicast watch will be registered - * @handler: Callback to call when a matching unicast is received - * @user_data: user data for the callback - * @destroy: Destroy callback for user data - * - * Adds a watch for unicast messages for a given family specified by @family. - * The watch can be registered even if the family has not been discovered yet - * or doesn't exist. - * - * Returns: a non-zero watch identifier that can be passed to - * l_genl_remove_unicast_watch to remove this watch, or zero if the - * watch could not be created successfully. - **/ -LIB_EXPORT unsigned int l_genl_add_unicast_watch(struct l_genl *genl, - const char *family, - l_genl_msg_func_t handler, - void *user_data, - l_genl_destroy_func_t destroy) -{ - struct unicast_watch *watch; - - if (unlikely(!genl || !family)) - return 0; - - if (strlen(family) >= GENL_NAMSIZ) - return 0; - - watch = l_new(struct unicast_watch, 1); - l_strlcpy(watch->name, family, GENL_NAMSIZ); - watch->handler = handler; - watch->destroy = destroy; - watch->user_data = user_data; - watch->id = get_next_id(&genl->next_watch_id); - l_queue_push_tail(genl->unicast_watches, watch); - - return watch->id; -} - -/** - * l_genl_remove_unicast_watch: - * @genl: GENL connection - * @id: unique identifier of the unicast watch to remove - * - * Removes the unicast watch. If a destroy callback was provided, then it is - * called in order to free any associated user data. - * - * Returns: #true if the watch was removed successfully and #false otherwise. - **/ -LIB_EXPORT bool l_genl_remove_unicast_watch(struct l_genl *genl, - unsigned int id) -{ - struct unicast_watch *watch; - - if (unlikely(!genl)) - return false; - - if (genl->in_unicast_watch_notify) { - watch = l_queue_find(genl->unicast_watches, unicast_watch_match, - L_UINT_TO_PTR(id)); - if (!watch) - return false; - - watch->id = 0; - return true; - } - - watch = l_queue_remove_if(genl->unicast_watches, unicast_watch_match, - L_UINT_TO_PTR(id)); - if (!watch) - return false; - - unicast_watch_free(watch); - - return true; -} - -/** - * l_genl_add_family_watch: - * @genl: GENL connection - * @name: Name of the family to watch for. Use NULL to match any family. - * @appeared_func: Callback to call when the matching family appears - * @vanished_func: Callback to call when the matching family disappears - * @user_data: user data for the callback - * @destroy: Destroy callback for user data - * - * Returns: a non-zero watch identifier that can be passed to - * l_genl_remove_family_watch to remove this watch, or zero if the - * watch could not be created successfully. - **/ -LIB_EXPORT unsigned int l_genl_add_family_watch(struct l_genl *genl, - const char *name, - l_genl_discover_func_t appeared_func, - l_genl_vanished_func_t vanished_func, - void *user_data, - l_genl_destroy_func_t destroy) -{ - struct family_watch *watch; - size_t len = 0; - - if (unlikely(!genl)) - return 0; - - if (name) { - len = strlen(name); - if (len >= GENL_NAMSIZ) - return 0; - } - - watch = l_new(struct family_watch, 1); - watch->name = l_strdup(name); - watch->appeared_func = appeared_func; - watch->vanished_func = vanished_func; - watch->user_data = user_data; - watch->destroy = destroy; - watch->id = get_next_id(&genl->next_watch_id); - l_queue_push_tail(genl->family_watches, watch); - - return watch->id; -} - -/** - * l_genl_remove_family_watch: - * @genl: GENL connection - * @id: unique identifier of the family watch to remove - * - * Removes the family watch. If a destroy callback was provided, then it is - * called in order to free any associated user data. - * - * Returns: #true if the watch was removed successfully and #false otherwise. - **/ -LIB_EXPORT bool l_genl_remove_family_watch(struct l_genl *genl, - unsigned int id) -{ - struct family_watch *watch; - - if (unlikely(!genl)) - return false; - - if (genl->in_family_watch_notify) { - watch = l_queue_find(genl->family_watches, family_watch_match, - L_UINT_TO_PTR(id)); - if (!watch) - return false; - - watch->id = 0; - return true; - } - - watch = l_queue_remove_if(genl->family_watches, family_watch_match, - L_UINT_TO_PTR(id)); - if (!watch) - return false; - - family_watch_free(watch); - - return true; -} - -struct family_request { - void *user_data; - l_genl_discover_func_t appeared_func; - l_genl_destroy_func_t destroy; - struct l_genl *genl; -}; - -static void request_family_callback(struct l_genl_msg *msg, void *user_data) -{ - struct family_request *req = user_data; - struct l_genl_family_info *info = family_info_new(NULL); - - if (parse_cmd_newfamily(info, msg) < 0) { - family_info_free(info); - - if (req->appeared_func) - req->appeared_func(NULL, req->user_data); - - return; - } - - info = family_info_update(req->genl, info); - - /* - * watch events should trigger as a result of new_family event. - * Do not trigger these here as the family might have already been - * discovered - */ - - if (req->appeared_func) - req->appeared_func(info, req->user_data); -} - -static void family_request_free(void *user_data) -{ - struct family_request *req = user_data; - - if (req->destroy) - req->destroy(req->user_data); - - l_free(req); -} - -/** - * l_genl_request_family: - * @genl: GENL connection - * @name: Name of the family to request - * @appeared_func: Callback to call - * @user_data: User data - * @destroy: Destroy callback for user_data - * - * Attempts to request a family given by @name. If the family is not currently - * available, then the kernel will attempt to auto-load the module for that - * family and if successful, the family will appear. If the family is already - * loaded, the kernel will not perform auto-loading. In both cases the callback - * is called with the family information. If auto-loading failed, a NULL - * will be given as a parameter to @appeared_func. - * - * Returns: #true if the request could be started successfully, - * false otherwise. - **/ -LIB_EXPORT bool l_genl_request_family(struct l_genl *genl, const char *name, - l_genl_discover_func_t appeared_func, - void *user_data, - l_genl_destroy_func_t destroy) -{ - size_t len; - struct l_genl_msg *msg; - struct family_request *req; - - if (unlikely(!genl) || unlikely(!name)) - return NULL; - - len = strlen(name); - if (unlikely(strlen(name) >= GENL_NAMSIZ)) - return NULL; - - req = l_new(struct family_request, 1); - req->appeared_func = appeared_func; - req->user_data = user_data; - req->destroy = destroy; - req->genl = genl; - - msg = l_genl_msg_new_sized(CTRL_CMD_GETFAMILY, - NLA_HDRLEN + GENL_NAMSIZ); - l_genl_msg_append_attr(msg, CTRL_ATTR_FAMILY_NAME, len + 1, name); - - if (l_genl_family_send(genl->nlctrl, msg, request_family_callback, - req, family_request_free) > 0) - return true; - - return false; -} - -const void *_genl_msg_as_bytes(struct l_genl_msg *msg, uint16_t type, - uint16_t flags, uint32_t seq, - uint32_t pid, - size_t *out_size) -{ - struct nlmsghdr *nlmsg; - struct genlmsghdr *genlmsg; - - nlmsg = msg->data; - - nlmsg->nlmsg_len = msg->len; - nlmsg->nlmsg_type = type; - nlmsg->nlmsg_flags = flags; - nlmsg->nlmsg_seq = seq; - nlmsg->nlmsg_pid = pid; - - genlmsg = msg->data + NLMSG_HDRLEN; - - genlmsg->cmd = msg->cmd; - genlmsg->version = msg->version; - - if (out_size) - *out_size = msg->len; - - return msg->data; -} - -LIB_EXPORT struct l_genl_msg *l_genl_msg_new(uint8_t cmd) -{ - return l_genl_msg_new_sized(cmd, 0); -} - -LIB_EXPORT struct l_genl_msg *l_genl_msg_new_sized(uint8_t cmd, uint32_t size) -{ - return msg_alloc(cmd, 0x00, size); -} - -LIB_EXPORT struct l_genl_msg *l_genl_msg_ref(struct l_genl_msg *msg) -{ - if (unlikely(!msg)) - return NULL; - - __sync_fetch_and_add(&msg->ref_count, 1); - - return msg; -} - -LIB_EXPORT void l_genl_msg_unref(struct l_genl_msg *msg) -{ - if (unlikely(!msg)) - return; - - if (__sync_sub_and_fetch(&msg->ref_count, 1)) - return; - - l_free(msg->data); - l_free(msg); -} - -LIB_EXPORT uint8_t l_genl_msg_get_command(struct l_genl_msg *msg) -{ - if (unlikely(!msg)) - return 0; - - return msg->cmd; -} - -LIB_EXPORT uint8_t l_genl_msg_get_version(struct l_genl_msg *msg) -{ - if (unlikely(!msg)) - return 0; - - return msg->version; -} - -LIB_EXPORT int l_genl_msg_get_error(struct l_genl_msg *msg) -{ - if (unlikely(!msg)) - return -ENOMSG; - - return msg->error; -} - -LIB_EXPORT bool l_genl_msg_append_attr(struct l_genl_msg *msg, uint16_t type, - uint16_t len, const void *data) -{ - struct nlattr *nla; - - if (unlikely(!msg)) - return false; - - if (!msg_grow(msg, NLA_HDRLEN + NLA_ALIGN(len))) - return false; - - nla = msg->data + msg->len; - nla->nla_len = NLA_HDRLEN + len; - nla->nla_type = type; - - if (len) - memcpy(msg->data + msg->len + NLA_HDRLEN, data, len); - - msg->len += NLA_HDRLEN + NLA_ALIGN(len); - - return true; -} - -LIB_EXPORT bool l_genl_msg_append_attrv(struct l_genl_msg *msg, uint16_t type, - const struct iovec *iov, - size_t iov_len) -{ - struct nlattr *nla; - size_t len = 0; - unsigned int i; - - if (unlikely(!msg)) - return false; - - for (i = 0; i < iov_len; i++) - len += iov[i].iov_len; - - if (!msg_grow(msg, NLA_HDRLEN + NLA_ALIGN(len))) - return false; - - nla = msg->data + msg->len; - nla->nla_len = NLA_HDRLEN + len; - nla->nla_type = type; - - msg->len += NLA_HDRLEN; - - for (i = 0; i < iov_len; i++, iov++) { - memcpy(msg->data + msg->len, iov->iov_base, iov->iov_len); - msg->len += iov->iov_len; - } - - msg->len += NLA_ALIGN(len) - len; - - return true; -} - -LIB_EXPORT bool l_genl_msg_enter_nested(struct l_genl_msg *msg, uint16_t type) -{ - if (unlikely(!msg)) - return false; - - if (unlikely(msg->nesting_level == MAX_NESTING_LEVEL)) - return false; - - if (!msg_grow(msg, NLA_HDRLEN)) - return false; - - msg->nests[msg->nesting_level].type = type; - msg->nests[msg->nesting_level].offset = msg->len; - msg->nesting_level += 1; - - msg->len += NLA_HDRLEN; - - return true; -} - -LIB_EXPORT bool l_genl_msg_leave_nested(struct l_genl_msg *msg) -{ - struct nlattr *nla; - - if (unlikely(!msg)) - return false; - - if (unlikely(msg->nesting_level == 0)) - return false; - - nla = msg->data + msg->nests[msg->nesting_level - 1].offset; - nla->nla_type = msg->nests[msg->nesting_level - 1].type; - nla->nla_len = msg->len - msg->nests[msg->nesting_level - 1].offset; - - msg->nesting_level -= 1; - - return true; -} - -#define NLA_OK(nla,len) ((len) >= (int) sizeof(struct nlattr) && \ - (nla)->nla_len >= sizeof(struct nlattr) && \ - (nla)->nla_len <= (len)) -#define NLA_NEXT(nla,attrlen) ((attrlen) -= NLMSG_ALIGN((nla)->nla_len), \ - (struct nlattr*)(((char*)(nla)) + \ - NLMSG_ALIGN((nla)->nla_len))) - -#define NLA_LENGTH(len) (NLMSG_ALIGN(sizeof(struct nlattr)) + (len)) -#define NLA_DATA(nla) ((void*)(((char*)(nla)) + NLA_LENGTH(0))) -#define NLA_PAYLOAD(nla) ((int)((nla)->nla_len) - NLA_LENGTH(0)) - -LIB_EXPORT bool l_genl_attr_init(struct l_genl_attr *attr, - struct l_genl_msg *msg) -{ - const struct nlattr *nla; - uint32_t len; - - if (unlikely(!attr) || unlikely(!msg)) - return false; - - if (!msg->data || msg->len < NLMSG_HDRLEN + GENL_HDRLEN) - return false; - - nla = msg->data + NLMSG_HDRLEN + GENL_HDRLEN; - len = msg->len - NLMSG_HDRLEN - GENL_HDRLEN; - - if (!NLA_OK(nla, len)) - return false; - - attr->msg = msg; - attr->data = NULL; - attr->len = 0; - attr->next_data = nla; - attr->next_len = len; - - return true; -} - -LIB_EXPORT bool l_genl_attr_next(struct l_genl_attr *attr, - uint16_t *type, - uint16_t *len, - const void **data) -{ - const struct nlattr *nla; - - if (unlikely(!attr)) - return false; - - nla = attr->next_data; - - if (!NLA_OK(nla, attr->next_len)) - return false; - - if (type) - *type = nla->nla_type & NLA_TYPE_MASK; - - if (len) - *len = NLA_PAYLOAD(nla); - - if (data) - *data = NLA_DATA(nla); - - attr->data = attr->next_data; - attr->len = attr->next_len; - - attr->next_data = NLA_NEXT(nla, attr->next_len); - - return true; -} - -LIB_EXPORT bool l_genl_attr_recurse(struct l_genl_attr *attr, - struct l_genl_attr *nested) -{ - const struct nlattr *nla; - - if (unlikely(!attr) || unlikely(!nested)) - return false; - - nla = attr->data; - if (!nla) - return false; - - nested->msg = attr->msg; - nested->data = NULL; - nested->len = 0; - nested->next_data = NLA_DATA(nla); - nested->next_len = NLA_PAYLOAD(nla); - - return true; -} - -/** - * l_genl_family_new: - * @genl: GENL connection - * @name: Name of the family for which a handle will be created - * - * Attempts to create a handle over which applications can send requests and - * listen to events from a given family. The family must have been discovered - * previously via @l_genl_discover_families or @l_genl_add_family_watch; or - * autoloaded using @l_genl_family_request. - * - * The destruction of the handle using @l_genl_family_free will clean up all - * requests started via this handle as well as unregister from any - * notifications. Notifications & Requests started by other handles will be - * unaffected. - * - * Returns: #NULL if the family handle could not be created and a valid - * handle on success. - **/ -LIB_EXPORT struct l_genl_family *l_genl_family_new(struct l_genl *genl, - const char *name) -{ - struct l_genl_family *family; - struct l_genl_family_info *info; - const struct l_queue_entry *entry; - - if (unlikely(!genl) || unlikely(!name)) - return NULL; - - for (entry = l_queue_get_entries(genl->family_infos); - entry; entry = entry->next) { - info = entry->data; - - if (!strncmp(name, info->name, GENL_NAMSIZ)) - break; - } - - if (!entry) - return NULL; - - family = family_alloc(genl, info->id); - - return family; -} - -LIB_EXPORT const struct l_genl_family_info *l_genl_family_get_info( - struct l_genl_family *family) -{ - if (unlikely(!family)) - return NULL; - - return l_queue_find(family->genl->family_infos, family_info_match, - L_UINT_TO_PTR(family->id)); -} - -LIB_EXPORT struct l_genl *l_genl_family_get_genl(struct l_genl_family *family) -{ - if (unlikely(!family)) - return 0; - - return family->genl; -} - -static unsigned int send_common(struct l_genl_family *family, uint16_t flags, - struct l_genl_msg *msg, l_genl_msg_func_t callback, - void *user_data, l_genl_destroy_func_t destroy) -{ - struct l_genl *genl; - struct genl_request *request; - - if (!family || !msg) - return 0; - - genl = family->genl; - if (!genl) - return 0; - - request = l_new(struct genl_request, 1); - request->type = family->id; - request->flags = NLM_F_REQUEST | flags; - request->msg = msg; - request->callback = callback; - request->destroy = destroy; - request->user_data = user_data; - request->id = get_next_id(&genl->next_request_id); - request->handle_id = family->handle_id; - l_queue_push_tail(genl->request_queue, request); - - wakeup_writer(genl); - - return request->id; -} - -LIB_EXPORT unsigned int l_genl_family_send(struct l_genl_family *family, - struct l_genl_msg *msg, - l_genl_msg_func_t callback, - void *user_data, - l_genl_destroy_func_t destroy) -{ - return send_common(family, NLM_F_ACK, msg, callback, - user_data, destroy); -} - -LIB_EXPORT unsigned int l_genl_family_dump(struct l_genl_family *family, - struct l_genl_msg *msg, - l_genl_msg_func_t callback, - void *user_data, - l_genl_destroy_func_t destroy) -{ - return send_common(family, NLM_F_ACK | NLM_F_DUMP, msg, callback, - user_data, destroy); -} - -LIB_EXPORT bool l_genl_family_cancel(struct l_genl_family *family, - unsigned int id) -{ - struct l_genl *genl; - struct genl_request *request; - - if (unlikely(!family) || unlikely(!id)) - return false; - - genl = family->genl; - if (!genl) - return false; - - request = l_queue_remove_if(genl->request_queue, match_request_id, - L_UINT_TO_PTR(id)); - if (request) - goto done; - - request = l_queue_remove_if(genl->pending_list, match_request_id, - L_UINT_TO_PTR(id)); - if (!request) - return false; - -done: - destroy_request(request); - - return true; -} - -static void add_membership(struct l_genl *genl, struct genl_mcast *mcast) -{ - int group = mcast->id; - - if (mcast->users > 0) - goto done; - - if (setsockopt(genl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, - &group, sizeof(group)) < 0) - return; - -done: - mcast->users++; -} - -static void drop_membership(struct l_genl *genl, struct genl_mcast *mcast) -{ - int group; - - if (--mcast->users) - return; - - group = mcast->id; - - setsockopt(genl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, - &group, sizeof(group)); -} - -LIB_EXPORT unsigned int l_genl_family_register(struct l_genl_family *family, - const char *group, - l_genl_msg_func_t callback, - void *user_data, - l_genl_destroy_func_t destroy) -{ - struct l_genl *genl; - struct l_genl_family_info *info; - struct mcast_notify *notify; - struct genl_mcast *mcast; - - if (unlikely(!family) || unlikely(!group)) - return 0; - - genl = family->genl; - if (!genl) - return 0; - - info = l_queue_find(genl->family_infos, family_info_match, - L_UINT_TO_PTR(family->id)); - if (!info) - return 0; - - mcast = l_queue_find(info->mcast_list, match_mcast_name, group); - if (!mcast) - return 0; - - notify = l_new(struct mcast_notify, 1); - notify->type = info->id; - notify->group = mcast->id; - notify->callback = callback; - notify->destroy = destroy; - notify->user_data = user_data; - notify->id = get_next_id(&genl->next_notify_id); - notify->handle_id = family->handle_id; - l_queue_push_tail(genl->notify_list, notify); - - add_membership(genl, mcast); - - return notify->id; -} - -LIB_EXPORT bool l_genl_family_unregister(struct l_genl_family *family, - unsigned int id) -{ - struct l_genl *genl; - struct mcast_notify *notify; - struct l_genl_family_info *info; - struct genl_mcast *mcast; - - if (unlikely(!family) || unlikely(!id)) - return false; - - genl = family->genl; - if (!genl) - return false; - - if (genl->in_mcast_notify) { - notify = l_queue_find(genl->notify_list, mcast_notify_match, - L_UINT_TO_PTR(id)); - if (!notify) - return false; - - notify->id = 0; - } else { - notify = l_queue_remove_if(genl->notify_list, - mcast_notify_match, - L_UINT_TO_PTR(id)); - if (!notify) - return false; - } - - info = l_queue_find(genl->family_infos, family_info_match, - L_UINT_TO_PTR(family->id)); - if (!info) - goto done; - - mcast = l_queue_find(info->mcast_list, match_mcast_id, - L_UINT_TO_PTR(notify->group)); - if (!mcast) - goto done; - - drop_membership(genl, mcast); - -done: - if (notify->id) - mcast_notify_free(notify); - - return true; -} - -LIB_EXPORT void l_genl_family_free(struct l_genl_family *family) -{ - struct l_genl *genl; - struct genl_request *req; - struct mcast_notify *notify; - struct l_genl_family_info *info; - - if (!family) - return; - - genl = family->genl; - info = l_queue_find(genl->family_infos, family_info_match, - L_UINT_TO_PTR(family->id)); - - while ((req = l_queue_remove_if(genl->pending_list, - match_request_hid, - L_UINT_TO_PTR(family->handle_id)))) - destroy_request(req); - - while ((req = l_queue_remove_if(genl->request_queue, - match_request_hid, - L_UINT_TO_PTR(family->handle_id)))) - destroy_request(req); - - while ((notify = l_queue_remove_if(genl->notify_list, - mcast_notify_match_by_hid, - L_UINT_TO_PTR(family->handle_id)))) { - struct genl_mcast *mcast = l_queue_find(info->mcast_list, - match_mcast_id, - L_UINT_TO_PTR(notify->group)); - - if (mcast) - drop_membership(genl, mcast); - - mcast_notify_free(notify); - } - - l_free(family); -} diff --git a/ell/genl.h b/ell/genl.h deleted file mode 100644 index 5df688b..0000000 --- a/ell/genl.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_GENL_H -#define __ELL_GENL_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_genl; -struct l_genl_family_info; -struct l_genl_family; -struct l_genl_msg; - -typedef void (*l_genl_destroy_func_t)(void *user_data); -typedef void (*l_genl_debug_func_t)(const char *str, void *user_data); -typedef void (*l_genl_msg_func_t)(struct l_genl_msg *msg, void *user_data); -typedef void (*l_genl_discover_func_t)(const struct l_genl_family_info *info, - void *user_data); -typedef void (*l_genl_vanished_func_t)(const char *name, void *user_data); - -struct l_genl *l_genl_new(void); -struct l_genl *l_genl_ref(struct l_genl *genl); -void l_genl_unref(struct l_genl *genl); - -bool l_genl_set_debug(struct l_genl *genl, l_genl_debug_func_t callback, - void *user_data, l_genl_destroy_func_t destroy); - -bool l_genl_discover_families(struct l_genl *genl, - l_genl_discover_func_t cb, void *user_data, - l_genl_destroy_func_t destroy); - -unsigned int l_genl_add_unicast_watch(struct l_genl *genl, - const char *family, - l_genl_msg_func_t handler, - void *user_data, - l_genl_destroy_func_t destroy); -bool l_genl_remove_unicast_watch(struct l_genl *genl, unsigned int id); - -unsigned int l_genl_add_family_watch(struct l_genl *genl, - const char *name, - l_genl_discover_func_t appeared_func, - l_genl_vanished_func_t vanished_func, - void *user_data, - l_genl_destroy_func_t destroy); -bool l_genl_remove_family_watch(struct l_genl *genl, unsigned int id); -bool l_genl_request_family(struct l_genl *genl, const char *name, - l_genl_discover_func_t appeared_func, - void *user_data, - l_genl_destroy_func_t destroy); - -struct l_genl_attr { - struct l_genl_msg *msg; - const void *data; - uint32_t len; - const void *next_data; - uint32_t next_len; -}; - -struct l_genl_msg* l_genl_msg_new(uint8_t cmd); -struct l_genl_msg *l_genl_msg_new_sized(uint8_t cmd, uint32_t size); - -struct l_genl_msg *l_genl_msg_ref(struct l_genl_msg *msg); -void l_genl_msg_unref(struct l_genl_msg *msg); - -uint8_t l_genl_msg_get_command(struct l_genl_msg *msg); -uint8_t l_genl_msg_get_version(struct l_genl_msg *msg); -int l_genl_msg_get_error(struct l_genl_msg *msg); - -bool l_genl_msg_append_attr(struct l_genl_msg *msg, uint16_t type, - uint16_t len, const void *data); -bool l_genl_msg_append_attrv(struct l_genl_msg *msg, uint16_t type, - const struct iovec *iov, size_t iov_len); -bool l_genl_msg_enter_nested(struct l_genl_msg *msg, uint16_t type); -bool l_genl_msg_leave_nested(struct l_genl_msg *msg); - -bool l_genl_attr_init(struct l_genl_attr *attr, struct l_genl_msg *msg); -bool l_genl_attr_next(struct l_genl_attr *attr, uint16_t *type, - uint16_t *len, const void **data); -bool l_genl_attr_recurse(struct l_genl_attr *attr, struct l_genl_attr *nested); - -bool l_genl_family_info_has_group(const struct l_genl_family_info *info, - const char *group); -bool l_genl_family_info_can_send(const struct l_genl_family_info *info, - uint8_t cmd); -bool l_genl_family_info_can_dump(const struct l_genl_family_info *info, - uint8_t cmd); -char **l_genl_family_info_get_groups(const struct l_genl_family_info *info); -uint32_t l_genl_family_info_get_id(const struct l_genl_family_info *info); -const char *l_genl_family_info_get_name(const struct l_genl_family_info *info); -uint32_t l_genl_family_info_get_version(const struct l_genl_family_info *info); - -struct l_genl_family *l_genl_family_new(struct l_genl *genl, const char *name); -void l_genl_family_free(struct l_genl_family *family); - -const struct l_genl_family_info *l_genl_family_get_info( - struct l_genl_family *family); - -struct l_genl *l_genl_family_get_genl(struct l_genl_family *family); - -unsigned int l_genl_family_send(struct l_genl_family *family, - struct l_genl_msg *msg, - l_genl_msg_func_t callback, - void *user_data, - l_genl_destroy_func_t destroy); -unsigned int l_genl_family_dump(struct l_genl_family *family, - struct l_genl_msg *msg, - l_genl_msg_func_t callback, - void *user_data, - l_genl_destroy_func_t destroy); -bool l_genl_family_cancel(struct l_genl_family *family, unsigned int id); - -unsigned int l_genl_family_register(struct l_genl_family *family, - const char *group, l_genl_msg_func_t callback, - void *user_data, l_genl_destroy_func_t destroy); -bool l_genl_family_unregister(struct l_genl_family *family, unsigned int id); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_GENL_H */ diff --git a/ell/gpio.c b/ell/gpio.c deleted file mode 100644 index c470ba9..0000000 --- a/ell/gpio.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2019 Geanix. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include - -#include "private.h" -#include "strv.h" -#include "util.h" -#include "gpio.h" - -struct l_gpio_chip { - int fd; - char *name; - char *label; - uint32_t n_lines; -}; - -struct l_gpio_writer { - int fd; - uint32_t n_offsets; -}; - -struct l_gpio_reader { - int fd; - uint32_t n_offsets; -}; - -static bool chip_has_line_label(const char *chip_name, const char *line_label) -{ - struct l_gpio_chip *chip; - bool has_label; - - chip = l_gpio_chip_new(chip_name); - if (!chip) - return false; - - has_label = l_gpio_chip_find_line_offset(chip, line_label, NULL); - - l_gpio_chip_free(chip); - - return has_label; -} - -LIB_EXPORT char **l_gpio_chips_with_line_label(const char *line_label) -{ - struct dirent *entry; - DIR *dp; - char **chips = NULL; - - dp = opendir("/sys/bus/gpio/devices"); - if (dp == NULL) - return NULL; - - while ((entry = readdir(dp))) { - if (entry->d_type != DT_LNK) - continue; - - if (!l_str_has_prefix(entry->d_name, "gpiochip")) - continue; - - if (chip_has_line_label(entry->d_name, line_label)) - chips = l_strv_append(chips, entry->d_name); - } - - closedir(dp); - - return chips; -} - -LIB_EXPORT struct l_gpio_chip *l_gpio_chip_new(const char *chip_name) -{ - struct l_gpio_chip *chip; - struct gpiochip_info info; - char *path; - int fd; - int ret; - - if (unlikely(!chip_name)) - return NULL; - - path = l_strdup_printf("/dev/%s", chip_name); - fd = open(path, O_RDONLY | O_CLOEXEC); - l_free(path); - - if (fd < 0) - return NULL; - - memset(&info, 0, sizeof(info)); - - ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &info); - if (ret < 0) { - close(fd); - return NULL; - } - - chip = l_new(struct l_gpio_chip, 1); - chip->fd = fd; - chip->n_lines = info.lines; - chip->label = l_strndup(info.label, sizeof(info.label)); - chip->name = l_strdup(chip_name); - - return chip; -} - -LIB_EXPORT const char *l_gpio_chip_get_label(struct l_gpio_chip *chip) -{ - if (unlikely(!chip)) - return NULL; - - return chip->label; -} - -LIB_EXPORT const char *l_gpio_chip_get_name(struct l_gpio_chip *chip) -{ - if (unlikely(!chip)) - return NULL; - - return chip->name; -} - -LIB_EXPORT uint32_t l_gpio_chip_get_num_lines(struct l_gpio_chip *chip) -{ - if (unlikely(!chip)) - return 0; - - return chip->n_lines; -} - -LIB_EXPORT void l_gpio_chip_free(struct l_gpio_chip *chip) -{ - if (unlikely(!chip)) - return; - - if (chip->fd >= 0) - close(chip->fd); - - l_free(chip->name); - l_free(chip->label); - l_free(chip); -} - -LIB_EXPORT bool l_gpio_chip_find_line_offset(struct l_gpio_chip *chip, - const char *line_label, - uint32_t *line_offset) -{ - struct gpioline_info info; - uint32_t i; - - if (unlikely(!chip)) - return false; - - if (unlikely(!line_label)) - return false; - - for (i = 0; i < chip->n_lines; i++) { - memset(&info, 0, sizeof(info)); - info.line_offset = i; - - if (ioctl(chip->fd, GPIO_GET_LINEINFO_IOCTL, &info) < 0) - return false; - - if (strcmp(info.name, line_label) != 0) - continue; - - if (line_offset) - *line_offset = i; - - return true; - } - - return false; -} - -LIB_EXPORT char *l_gpio_chip_get_line_label(struct l_gpio_chip *chip, - uint32_t offset) -{ - struct gpioline_info info; - - if (unlikely(!chip)) - return NULL; - - if (unlikely(offset >= chip->n_lines)) - return NULL; - - memset(&info, 0, sizeof(info)); - info.line_offset = offset; - - if (ioctl(chip->fd, GPIO_GET_LINEINFO_IOCTL, &info) < 0) - return NULL; - - return l_strdup(info.name); -} - -LIB_EXPORT char *l_gpio_chip_get_line_consumer(struct l_gpio_chip *chip, - uint32_t offset) -{ - struct gpioline_info info; - - if (unlikely(!chip)) - return NULL; - - if (unlikely(offset >= chip->n_lines)) - return NULL; - - memset(&info, 0, sizeof(info)); - info.line_offset = offset; - - if (ioctl(chip->fd, GPIO_GET_LINEINFO_IOCTL, &info) < 0) - return NULL; - - return l_strdup(info.consumer); -} - -LIB_EXPORT struct l_gpio_writer *l_gpio_writer_new(struct l_gpio_chip *chip, - const char *consumer, - uint32_t n_offsets, - const uint32_t offsets[], - const uint32_t values[]) -{ - struct l_gpio_writer *writer; - struct gpiohandle_request request; - uint32_t i; - - if (unlikely(!chip)) - return NULL; - - if (unlikely(n_offsets == 0 || n_offsets > GPIOHANDLES_MAX)) - return NULL; - - if (unlikely(!offsets)) - return NULL; - - memset(&request, 0, sizeof(request)); - l_strlcpy(request.consumer_label, consumer, 32); - request.lines = n_offsets; - request.flags = GPIOHANDLE_REQUEST_OUTPUT; - - for (i = 0; i < n_offsets; i++) { - if (offsets[i] >= chip->n_lines) - return NULL; - - request.lineoffsets[i] = offsets[i]; - request.default_values[i] = values[i]; - } - - if (ioctl(chip->fd, GPIO_GET_LINEHANDLE_IOCTL, &request) < 0) - return NULL; - - if (request.fd <= 0) - return NULL; - - writer = l_new(struct l_gpio_writer, 1); - writer->fd = request.fd; - writer->n_offsets = n_offsets; - - return writer; -} - -LIB_EXPORT void l_gpio_writer_free(struct l_gpio_writer *writer) -{ - if (unlikely(!writer)) - return; - - if (writer->fd >= 0) - close(writer->fd); - - l_free(writer); -} - -LIB_EXPORT bool l_gpio_writer_set(struct l_gpio_writer *writer, uint32_t n_values, - const uint32_t values[]) -{ - struct gpiohandle_data data; - uint32_t i; - - if (unlikely(!writer)) - return false; - - if (unlikely(!values)) - return false; - - if (unlikely(n_values != writer->n_offsets)) - return false; - - for (i = 0; i < n_values; i++) - data.values[i] = values[i]; - - if (ioctl(writer->fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data) < 0) - return false; - - return true; -} - -LIB_EXPORT struct l_gpio_reader *l_gpio_reader_new(struct l_gpio_chip *chip, - const char *consumer, - uint32_t n_offsets, - const uint32_t offsets[]) -{ - struct l_gpio_reader *reader; - struct gpiohandle_request request; - uint32_t i; - - if (unlikely(!chip)) - return NULL; - - if (unlikely(n_offsets == 0 || n_offsets > GPIOHANDLES_MAX)) - return NULL; - - if (unlikely(!offsets)) - return NULL; - - memset(&request, 0, sizeof(request)); - l_strlcpy(request.consumer_label, consumer, 32); - request.lines = n_offsets; - request.flags = GPIOHANDLE_REQUEST_INPUT; - - for (i = 0; i < n_offsets; i++) { - if (offsets[i] >= chip->n_lines) - return NULL; - - request.lineoffsets[i] = offsets[i]; - } - - if (ioctl(chip->fd, GPIO_GET_LINEHANDLE_IOCTL, &request) < 0) - return NULL; - - if (request.fd <= 0) - return NULL; - - reader = l_new(struct l_gpio_reader, 1); - reader->fd = request.fd; - reader->n_offsets = n_offsets; - - return reader; -} - -LIB_EXPORT void l_gpio_reader_free(struct l_gpio_reader *reader) -{ - if (unlikely(!reader)) - return; - - if (reader->fd >= 0) - close(reader->fd); - - l_free(reader); -} - -LIB_EXPORT bool l_gpio_reader_get(struct l_gpio_reader *reader, - uint32_t n_values, uint32_t values[]) -{ - struct gpiohandle_data data; - uint32_t i; - - if (unlikely(!reader)) - return false; - - if (unlikely(n_values != reader->n_offsets)) - return false; - - if (unlikely(!values)) - return false; - - if (ioctl(reader->fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data) < 0) - return false; - - for (i = 0; i < n_values; i++) - values[i] = data.values[i]; - - return true; -} diff --git a/ell/gpio.h b/ell/gpio.h deleted file mode 100644 index 4912519..0000000 --- a/ell/gpio.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2019 Geanix. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_GPIO_H -#define __ELL_GPIO_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_gpio_chip; -struct l_gpio_writer; -struct l_gpio_reader; - -char **l_gpio_chips_with_line_label(const char *line_label); -struct l_gpio_chip *l_gpio_chip_new(const char *chip_name); -void l_gpio_chip_free(struct l_gpio_chip *chip); -const char *l_gpio_chip_get_label(struct l_gpio_chip *chip); -const char *l_gpio_chip_get_name(struct l_gpio_chip *chip); -uint32_t l_gpio_chip_get_num_lines(struct l_gpio_chip *chip); -bool l_gpio_chip_find_line_offset(struct l_gpio_chip *chip, - const char *line_label, - uint32_t *line_offset); -char *l_gpio_chip_get_line_label(struct l_gpio_chip *chip, uint32_t offset); -char *l_gpio_chip_get_line_consumer(struct l_gpio_chip *chip, uint32_t offset); - -struct l_gpio_writer *l_gpio_writer_new(struct l_gpio_chip *chip, - const char *consumer, - uint32_t n_offsets, - const uint32_t offsets[], - const uint32_t values[]); -void l_gpio_writer_free(struct l_gpio_writer *writer); -bool l_gpio_writer_set(struct l_gpio_writer *writer, uint32_t n_values, - const uint32_t values[]); - -struct l_gpio_reader *l_gpio_reader_new(struct l_gpio_chip *chip, - const char *consumer, - uint32_t n_offsets, - const uint32_t offsets[]); -void l_gpio_reader_free(struct l_gpio_reader *reader); -bool l_gpio_reader_get(struct l_gpio_reader *reader, uint32_t n_values, - uint32_t values[]); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_GPIO_H */ diff --git a/ell/gvariant-private.h b/ell/gvariant-private.h deleted file mode 100644 index 6c0005a..0000000 --- a/ell/gvariant-private.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -struct l_dbus_message_iter; -struct dbus_builder; - -bool _gvariant_iter_init(struct l_dbus_message_iter *iter, - struct l_dbus_message *message, - const char *sig_start, const char *sig_end, - const void *data, size_t len); -bool _gvariant_iter_next_entry_basic(struct l_dbus_message_iter *iter, - char type, void *out_p); -bool _gvariant_iter_enter_struct(struct l_dbus_message_iter *iter, - struct l_dbus_message_iter *structure); -bool _gvariant_iter_enter_variant(struct l_dbus_message_iter *iter, - struct l_dbus_message_iter *variant); -bool _gvariant_iter_enter_array(struct l_dbus_message_iter *iter, - struct l_dbus_message_iter *array); -bool _gvariant_iter_skip_entry(struct l_dbus_message_iter *iter); - -bool _gvariant_valid_signature(const char *sig); -int _gvariant_get_alignment(const char *signature); -bool _gvariant_is_fixed_size(const char *signature); -int _gvariant_get_fixed_size(const char *signature); -int _gvariant_num_children(const char *sig); - -struct dbus_builder *_gvariant_builder_new(void *body, size_t body_size); -void _gvariant_builder_free(struct dbus_builder *builder); -bool _gvariant_builder_append_basic(struct dbus_builder *builder, - char type, const void *value); -bool _gvariant_builder_mark(struct dbus_builder *builder); -bool _gvariant_builder_rewind(struct dbus_builder *builder); -char *_gvariant_builder_finish(struct dbus_builder *builder, - void **body, size_t *body_size); -bool _gvariant_builder_enter_struct(struct dbus_builder *builder, - const char *signature); -bool _gvariant_builder_leave_struct(struct dbus_builder *builder); -bool _gvariant_builder_enter_dict(struct dbus_builder *builder, - const char *signature); -bool _gvariant_builder_leave_dict(struct dbus_builder *builder); -bool _gvariant_builder_enter_variant(struct dbus_builder *builder, - const char *signature); -bool _gvariant_builder_leave_variant(struct dbus_builder *builder); -bool _gvariant_builder_enter_array(struct dbus_builder *builder, - const char *signature); -bool _gvariant_builder_leave_array(struct dbus_builder *builder); - -size_t _gvariant_message_finalize(size_t header_end, - void *body, size_t body_size, - const char *signature); diff --git a/ell/gvariant-util.c b/ell/gvariant-util.c deleted file mode 100644 index ed6b72e..0000000 --- a/ell/gvariant-util.c +++ /dev/null @@ -1,1384 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include - -#include "private.h" -#include "util.h" -#include "queue.h" -#include "string.h" -#include "log.h" -#include "dbus.h" -#include "dbus-private.h" -#include "gvariant-private.h" - -static const char *simple_types = "sogybnqiuxtdh"; -static const char *variable_types = "sogav"; -static const char *fixed_types = "bynqhiuxtd"; - -/* - * The alignment of a container type is equal to the largest alignment of - * any potential child of that container. This means that, even if an array - * of 32-bit integers is empty, it still must be aligned to the nearest - * multiple of 4 bytes. It also means that the variant type (described below) - * has an alignment of 8 (since it could potentially contain a value of any - * other type and the maximum alignment is 8). - */ -static int get_basic_alignment(const char type) -{ - switch (type) { - case 'b': - return 1; - case 'y': - return 1; - case 'n': - case 'q': - return 2; - case 'i': - case 'u': - return 4; - case 'x': - case 't': - case 'd': - return 8; - case 's': - case 'g': - case 'o': - return 1; - case 'h': - return 4; - case 'v': - return 8; - default: - return 0; - } -} - -static int get_basic_fixed_size(const char type) -{ - switch (type) { - case 'b': - return 1; - case 'y': - return 1; - case 'n': - case 'q': - return 2; - case 'i': - case 'u': - return 4; - case 'x': - case 't': - case 'd': - return 8; - case 'h': - return 4; - default: - return 0; - } -} - -static const char *validate_next_type(const char *sig, int *out_alignment) -{ - char s = *sig; - int alignment; - - if (s == '\0') - return NULL; - - if (strchr(simple_types, s) || s == 'v') { - *out_alignment = get_basic_alignment(s); - return sig + 1; - } - - switch (s) { - case 'a': - return validate_next_type(++sig, out_alignment); - - case '{': - s = *++sig; - - /* Dictionary keys can only be simple types */ - if (!strchr(simple_types, s)) - return NULL; - - alignment = get_basic_alignment(s); - - sig = validate_next_type(sig + 1, out_alignment); - - if (!sig) - return NULL; - - if (*sig != '}') - return NULL; - - if (alignment > *out_alignment) - *out_alignment = alignment; - - return sig + 1; - - case '(': - { - int max_alignment = 1, alignment; - - sig++; - - while (sig && *sig != ')') { - sig = validate_next_type(sig, &alignment); - - if (alignment > max_alignment) - max_alignment = alignment; - } - - if (!sig) - return NULL; - - if (*sig != ')') - return NULL; - - *out_alignment = max_alignment; - - return sig + 1; - } - } - - return NULL; -} - -bool _gvariant_valid_signature(const char *sig) -{ - const char *s = sig; - int a; - - if (strlen(sig) > 255) - return false; - - do { - s = validate_next_type(s, &a); - - if (!s) - return false; - } while (*s); - - return true; -} - -int _gvariant_num_children(const char *sig) -{ - const char *s = sig; - int a; - int num_children = 0; - - if (strlen(sig) > 255) - return false; - - do { - s = validate_next_type(s, &a); - - if (!s) - return -1; - - num_children += 1; - } while (*s); - - return num_children; -} - -int _gvariant_get_alignment(const char *sig) -{ - int max_alignment = 1, alignment; - const char *s = sig; - - /* 8 is the largest alignment possible, so quit if we reach it */ - while (*s && max_alignment != 8) { - s = validate_next_type(s, &alignment); - if (!s) - return 0; - - if (alignment > max_alignment) - max_alignment = alignment; - } - - return max_alignment; -} - -bool _gvariant_is_fixed_size(const char *sig) -{ - while (*sig != 0) { - if (strchr(variable_types, sig[0])) - return false; - - sig += 1; - } - - return true; -} - -int _gvariant_get_fixed_size(const char *sig) -{ - const char *s = sig; - const char *p; - int size = 0; - int alignment; - int max_alignment = 1; - int r; - - while (*s) { - if (strchr(variable_types, *s)) - return 0; - - if (strchr(fixed_types, *s)) { - alignment = get_basic_alignment(*s); - - if (alignment > max_alignment) - max_alignment = alignment; - - size = align_len(size, alignment); - size += get_basic_fixed_size(*s); - s++; - continue; - } - - if (*s == '}' || *s == ')') - break; - - p = validate_next_type(s, &alignment); - - if (!p) - return 0; - - if (alignment > max_alignment) - max_alignment = alignment; - - size = align_len(size, alignment); - - /* Handle special case of unit type */ - if (s[0] == '(' && s[1] == ')') - r = 1; - else - r = _gvariant_get_fixed_size(s + 1); - - if (r == 0) - return 0; - - size += r; - s = p; - } - - size = align_len(size, max_alignment); - - return size; -} - -static inline size_t offset_length(size_t size, size_t n_offsets) -{ - if (size + n_offsets <= 0xff) - return 1; - if (size + n_offsets * 2 <= 0xffff) - return 2; - if (size + n_offsets * 4 <= 0xffffffff) - return 4; - else - return 8; -} - -static inline size_t read_word_le(const void *p, size_t sz) { - union { - uint16_t u16; - uint32_t u32; - uint64_t u64; - } x; - - if (sz == 1) - return *(uint8_t *) p; - - memcpy(&x, p, sz); - - if (sz == 2) - return le16toh(x.u16); - else if (sz == 4) - return le32toh(x.u32); - else - return le64toh(x.u64); -} - -static inline void write_word_le(void *p, size_t value, size_t sz) { - union { - uint16_t u16; - uint32_t u32; - uint64_t u64; - } x; - - if (sz == 1) { - *(uint8_t *) p = value; - return; - } - - if (sz == 2) - x.u16 = htole16((uint16_t) value); - else if (sz == 4) - x.u32 = htole32((uint32_t) value); - else - x.u64 = htole64((uint64_t) value); - - memcpy(p, &x, sz); -} - -static bool gvariant_iter_init_internal(struct l_dbus_message_iter *iter, - struct l_dbus_message *message, - enum dbus_container_type type, - const char *sig_start, - const char *sig_end, const void *data, - size_t len) -{ - const char *p; - int i; - int v; - char subsig[256]; - unsigned int num_variable = 0; - unsigned int offset_len = offset_length(len, 0); - size_t last_offset; - struct gvariant_type_info { - uint8_t sig_start; - uint8_t sig_end; - bool fixed_size : 1; - unsigned int alignment : 4; - size_t end; /* Index past the end of the type */ - } *children; - int n_children; - - if (sig_end) { - size_t len = sig_end - sig_start; - memcpy(subsig, sig_start, len); - subsig[len] = '\0'; - } else - strcpy(subsig, sig_start); - - iter->message = message; - iter->sig_start = sig_start; - iter->sig_len = strlen(subsig); - iter->sig_pos = 0; - iter->data = data; - iter->len = len; - iter->pos = 0; - - if (subsig[0] != '\0') { - n_children = _gvariant_num_children(subsig); - if (n_children < 0) - return false; - - children = l_new(struct gvariant_type_info, n_children); - } else { - n_children = 0; - - children = NULL; - } - - for (p = sig_start, i = 0; i < n_children; i++) { - int alignment; - size_t size; - size_t len; - - children[i].sig_start = p - sig_start; - p = validate_next_type(p, &alignment); - children[i].sig_end = p - sig_start; - - len = children[i].sig_end - children[i].sig_start; - memcpy(subsig, sig_start + children[i].sig_start, len); - subsig[len] = '\0'; - - children[i].alignment = alignment; - children[i].fixed_size = _gvariant_is_fixed_size(subsig); - - if (children[i].fixed_size) { - size = _gvariant_get_fixed_size(subsig); - children[i].end = size; - } else if (i + 1 < n_children) - num_variable += 1; - } - - if (len < num_variable * offset_len) - goto fail; - - last_offset = len - num_variable * offset_len; - - if (num_variable > 0) - iter->offsets = iter->data + len - offset_len; - else - iter->offsets = NULL; - - for (i = 0, v = 0; i < n_children; i++) { - size_t o; - - if (children[i].fixed_size) { - if (i == 0) - continue; - - o = align_len(children[i-1].end, - children[i].alignment); - children[i].end += o; - - if (children[i].end > len) - goto fail; - - continue; - } - - if (num_variable == 0) { - children[i].end = last_offset; - continue; - } - - v += 1; - children[i].end = read_word_le(data + len - offset_len * v, - offset_len); - num_variable -= 1; - - if (children[i].end > len) - goto fail; - } - - iter->container_type = type; - - if (type == DBUS_CONTAINER_TYPE_ARRAY && - !children[0].fixed_size) { - size_t offset = read_word_le(iter->data + iter->len - - offset_len, offset_len); - iter->offsets = iter->data + offset; - } - - l_free(children); - - return true; - -fail: - l_free(children); - return false; -} - -bool _gvariant_iter_init(struct l_dbus_message_iter *iter, - struct l_dbus_message *message, - const char *sig_start, const char *sig_end, - const void *data, size_t len) -{ - return gvariant_iter_init_internal(iter, message, - DBUS_CONTAINER_TYPE_STRUCT, - sig_start, sig_end, data, len); -} - -static const void *next_item(struct l_dbus_message_iter *iter, - size_t *out_item_size) -{ - const void *start; - const char *p; - char sig[256]; - int alignment; - bool fixed_size; - bool last_member; - unsigned int sig_len; - unsigned int offset_len; - - memcpy(sig, iter->sig_start + iter->sig_pos, - iter->sig_len - iter->sig_pos); - sig[iter->sig_len - iter->sig_pos] = '\0'; - - /* - * Find the next type and make a note whether it is the last in the - * structure. Arrays will always have a single complete type, so - * last_member will always be true. - */ - p = validate_next_type(sig, &alignment); - if (!p) - return NULL; - - sig_len = p - sig; - - last_member = *p == '\0'; - sig[sig_len] = '\0'; - - fixed_size = _gvariant_is_fixed_size(sig); - - if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY) - iter->sig_pos += sig_len; - - iter->pos = align_len(iter->pos, alignment); - - if (fixed_size) { - *out_item_size = _gvariant_get_fixed_size(sig); - goto done; - } - - if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY && last_member) { - unsigned int len = iter->len; - - offset_len = offset_length(iter->len, 0); - - if (iter->offsets && iter->offsets + offset_len < - iter->data + len) - len = iter->offsets + offset_len - iter->data; - - *out_item_size = len - iter->pos; - goto done; - } - - if (iter->offsets >= iter->data + iter->len) - return NULL; - - offset_len = offset_length(iter->len, 0); - *out_item_size = read_word_le(iter->offsets, offset_len) - iter->pos; - - /* In structures the offsets are in reverse order */ - if (iter->container_type == DBUS_CONTAINER_TYPE_ARRAY) - iter->offsets += offset_len; - else - iter->offsets -= offset_len; - -done: - start = iter->data + iter->pos; - - if (start >= iter->data + iter->len) - return NULL; - - iter->pos += *out_item_size; - - return start; -} - -bool _gvariant_iter_next_entry_basic(struct l_dbus_message_iter *iter, - char type, void *out) -{ - size_t item_size = 0; - const void *start; - uint8_t uint8_val; - uint16_t uint16_val; - uint32_t uint32_val; - uint64_t uint64_val; - int16_t int16_val; - int32_t int32_val; - int64_t int64_val; - - if (iter->pos >= iter->len) - return false; - - if (iter->sig_start[iter->sig_pos] != type) - return false; - - start = next_item(iter, &item_size); - if (!start) - return false; - - switch (type) { - case 'o': - case 's': - case 'g': - { - const void *end = memchr(start, 0, item_size); - - if (!end) - return false; - - *(const char**) out = start; - break; - } - case 'b': - uint8_val = l_get_u8(start); - *(bool *) out = !!uint8_val; - break; - case 'y': - uint8_val = l_get_u8(start); - *(uint8_t *) out = uint8_val; - break; - case 'n': - int16_val = l_get_s16(start); - *(int16_t *) out = int16_val; - break; - case 'q': - uint16_val = l_get_u16(start); - *(uint16_t *) out = uint16_val; - break; - case 'i': - int32_val = l_get_s32(start); - *(int32_t *) out = int32_val; - break; - case 'h': - case 'u': - uint32_val = l_get_u32(start); - *(uint32_t *) out = uint32_val; - break; - case 'x': - int64_val = l_get_s64(start); - *(int64_t *) out = int64_val; - break; - case 't': - uint64_val = l_get_u64(start); - *(uint64_t *) out = uint64_val; - break; - case 'd': - uint64_val = l_get_u64(start); - *(uint64_t *) out = uint64_val; - break; - } - - return true; -} - -bool _gvariant_iter_enter_struct(struct l_dbus_message_iter *iter, - struct l_dbus_message_iter *structure) -{ - bool is_dict = iter->sig_start[iter->sig_pos] == '{'; - bool is_struct = iter->sig_start[iter->sig_pos] == '('; - const char *sig_start = iter->sig_start + iter->sig_pos + 1; - const char *sig_end; - const void *start; - size_t item_size; - enum dbus_container_type type; - - if (!is_dict && !is_struct) - return false; - - start = next_item(iter, &item_size); - if (!start) - return false; - - /* For ARRAY containers the sig_pos is never incremented */ - if (iter->container_type == DBUS_CONTAINER_TYPE_ARRAY) - sig_end = iter->sig_start + iter->sig_len - 1; - else - sig_end = iter->sig_start + iter->sig_pos - 1; - - type = is_dict ? DBUS_CONTAINER_TYPE_DICT_ENTRY : - DBUS_CONTAINER_TYPE_STRUCT; - - return gvariant_iter_init_internal(structure, iter->message, - type, sig_start, sig_end, - start, item_size); -} - -bool _gvariant_iter_enter_variant(struct l_dbus_message_iter *iter, - struct l_dbus_message_iter *variant) -{ - size_t item_size; - const void *start, *end, *nul; - char signature[256]; - - if (iter->sig_start[iter->sig_pos] != 'v') - return false; - - start = next_item(iter, &item_size); - if (!start) - return false; - - /* Find the signature */ - end = start + item_size; - nul = memrchr(start, 0, end - start); - - if (!nul) - return false; - - if (end - nul - 1 > 255) - return false; - - memcpy(signature, nul + 1, end - nul - 1); - signature[end - nul - 1] = '\0'; - - if (_gvariant_num_children(signature) != 1) - return false; - - return gvariant_iter_init_internal(variant, iter->message, - DBUS_CONTAINER_TYPE_VARIANT, - nul + 1, end, - start, nul - start); -} - -bool _gvariant_iter_enter_array(struct l_dbus_message_iter *iter, - struct l_dbus_message_iter *array) -{ - const char *sig_start; - const char *sig_end; - size_t item_size; - const void *start; - - if (iter->sig_start[iter->sig_pos] != 'a') - return false; - - sig_start = iter->sig_start + iter->sig_pos + 1; - - start = next_item(iter, &item_size); - if (!start) - return false; - - /* For ARRAY containers the sig_pos is never incremented */ - if (iter->container_type == DBUS_CONTAINER_TYPE_ARRAY) - sig_end = iter->sig_start + iter->sig_len; - else - sig_end = iter->sig_start + iter->sig_pos; - - return gvariant_iter_init_internal(array, iter->message, - DBUS_CONTAINER_TYPE_ARRAY, - sig_start, sig_end, - start, item_size); -} - -bool _gvariant_iter_skip_entry(struct l_dbus_message_iter *iter) -{ - size_t size; - - if (!next_item(iter, &size)) - return false; - - return true; -} - -struct dbus_builder { - struct l_string *signature; - void *body; - size_t body_size; - size_t body_pos; - struct l_queue *containers; - struct { - struct container *container; - int sig_end; - size_t body_pos; - size_t offset_index; - bool variable_is_last : 1; - } mark; -}; - -struct container { - size_t *offsets; - size_t offsets_size; - size_t offset_index; - size_t start; - bool variable_is_last : 1; - enum dbus_container_type type; - char signature[256]; - uint8_t sigindex; -}; - -static inline size_t grow_body(struct dbus_builder *builder, - size_t len, unsigned int alignment) -{ - size_t size = align_len(builder->body_pos, alignment); - - if (size + len > builder->body_size) { - builder->body = l_realloc(builder->body, size + len); - builder->body_size = size + len; - } - - if (size - builder->body_pos > 0) - memset(builder->body + builder->body_pos, 0, - size - builder->body_pos); - - builder->body_pos = size + len; - - return size; -} - -static inline bool grow_offsets(struct container *container) -{ - size_t needed; - - if (container->offset_index < container->offsets_size) - return true; - - needed = container->offsets_size * 2; - - if (needed > USHRT_MAX) - return false; - - if (needed == 0) - needed = 8; - - container->offsets = l_realloc(container->offsets, - needed * sizeof(size_t)); - container->offsets_size = needed; - - return true; -} - -static struct container *container_new(enum dbus_container_type type, - const char *signature, size_t start) -{ - struct container *ret; - - ret = l_new(struct container, 1); - - ret->type = type; - strcpy(ret->signature, signature); - ret->start = start; - - return ret; -} - -static void container_free(struct container *container) -{ - l_free(container->offsets); - l_free(container); -} - -static void container_append_struct_offsets(struct container *container, - struct dbus_builder *builder) -{ - size_t offset_size; - int i; - size_t start; - - if (container->variable_is_last) - container->offset_index -= 1; - - if (container->offset_index == 0) - return; - - offset_size = offset_length(builder->body_pos, - container->offset_index); - i = container->offset_index - 1; - - start = grow_body(builder, offset_size * container->offset_index, 1); - - for (i = container->offset_index - 1; i >= 0; i--) { - write_word_le(builder->body + start, - container->offsets[i], offset_size); - start += offset_size; - } -} - -static void container_append_array_offsets(struct container *container, - struct dbus_builder *builder) -{ - size_t offset_size; - unsigned int i; - size_t start; - - if (container->offset_index == 0) - return; - - offset_size = offset_length(builder->body_pos, - container->offset_index); - start = grow_body(builder, offset_size * container->offset_index, 1); - - for (i = 0; i < container->offset_index; i++) { - write_word_le(builder->body + start, - container->offsets[i], offset_size); - start += offset_size; - } -} - -struct dbus_builder *_gvariant_builder_new(void *body, size_t body_size) -{ - struct dbus_builder *builder; - struct container *root; - - builder = l_new(struct dbus_builder, 1); - builder->signature = l_string_new(63); - - builder->containers = l_queue_new(); - root = container_new(DBUS_CONTAINER_TYPE_STRUCT, "", 0); - l_queue_push_head(builder->containers, root); - - builder->body = body; - builder->body_size = body_size; - builder->body_pos = body_size; - - builder->mark.container = root; - - return builder; -} - -void _gvariant_builder_free(struct dbus_builder *builder) -{ - if (unlikely(!builder)) - return; - - l_string_free(builder->signature); - l_queue_destroy(builder->containers, - (l_queue_destroy_func_t) container_free); - l_free(builder->body); - - l_free(builder); -} - -static bool enter_struct_dict_common(struct dbus_builder *builder, - const char *signature, - enum dbus_container_type type, - const char open, - const char close) -{ - size_t qlen = l_queue_length(builder->containers); - struct container *container = l_queue_peek_head(builder->containers); - int alignment; - size_t start; - - if (qlen == 1) { - if (l_string_length(builder->signature) + - strlen(signature) + 2 > 255) - return false; - } else { - /* Verify Signatures Match */ - char expect[256]; - const char *start; - const char *end; - - start = container->signature + container->sigindex; - end = validate_next_type(start, &alignment) - 1; - - if (*start != open || *end != close) - return false; - - memcpy(expect, start + 1, end - start - 1); - expect[end - start - 1] = '\0'; - - if (strcmp(expect, signature)) - return false; - } - - alignment = _gvariant_get_alignment(signature); - start = grow_body(builder, 0, alignment); - - container = container_new(type, signature, start); - l_queue_push_head(builder->containers, container); - - return true; -} - -bool _gvariant_builder_enter_struct(struct dbus_builder *builder, - const char *signature) -{ - if (signature[0] && !_gvariant_valid_signature(signature)) - return false; - - return enter_struct_dict_common(builder, signature, - DBUS_CONTAINER_TYPE_STRUCT, '(', ')'); -} - -bool _gvariant_builder_enter_dict(struct dbus_builder *builder, - const char *signature) -{ - if (_gvariant_num_children(signature) != 2) - return false; - - if (!strchr(simple_types, signature[0])) - return false; - - return enter_struct_dict_common(builder, signature, - DBUS_CONTAINER_TYPE_DICT_ENTRY, - '{', '}'); -} - -static bool leave_struct_dict_common(struct dbus_builder *builder, - enum dbus_container_type type, - const char open, - const char close) -{ - struct container *container = l_queue_peek_head(builder->containers); - size_t qlen = l_queue_length(builder->containers); - struct container *parent; - - if (unlikely(qlen <= 1)) - return false; - - if (unlikely(container->type != type)) - return false; - - l_queue_pop_head(builder->containers); - qlen -= 1; - parent = l_queue_peek_head(builder->containers); - - if (_gvariant_is_fixed_size(container->signature)) { - int alignment = _gvariant_get_alignment(container->signature); - grow_body(builder, 0, alignment); - - /* Empty struct or "unit type" is encoded as a zero byte */ - if (container->signature[0] == '\0') { - size_t start = grow_body(builder, 1, 1); - - memset(builder->body + start, 0, 1); - } - - parent->variable_is_last = false; - } else { - size_t offset; - - if (!grow_offsets(parent)) - return false; - - container_append_struct_offsets(container, builder); - offset = builder->body_pos - parent->start; - parent->offsets[parent->offset_index++] = offset; - parent->variable_is_last = true; - } - - if (qlen == 1) - l_string_append_printf(builder->signature, "%c%s%c", - open, - container->signature, - close); - else if (parent->type != DBUS_CONTAINER_TYPE_ARRAY) - parent->sigindex += strlen(container->signature) + 2; - - container_free(container); - - return true; -} - -bool _gvariant_builder_leave_struct(struct dbus_builder *builder) -{ - return leave_struct_dict_common(builder, DBUS_CONTAINER_TYPE_STRUCT, - '(', ')'); -} - -bool _gvariant_builder_leave_dict(struct dbus_builder *builder) -{ - return leave_struct_dict_common(builder, - DBUS_CONTAINER_TYPE_DICT_ENTRY, - '{', '}'); -} - -bool _gvariant_builder_enter_variant(struct dbus_builder *builder, - const char *signature) -{ - size_t qlen = l_queue_length(builder->containers); - struct container *container = l_queue_peek_head(builder->containers); - size_t start; - - if (_gvariant_num_children(signature) != 1) - return false; - - if (qlen == 1) { - if (l_string_length(builder->signature) + 1 > 255) - return false; - } else if (container->signature[container->sigindex] != 'v') - return false; - - start = grow_body(builder, 0, 8); - - container = container_new(DBUS_CONTAINER_TYPE_VARIANT, - signature, start); - l_queue_push_head(builder->containers, container); - - return true; -} - -bool _gvariant_builder_leave_variant(struct dbus_builder *builder) -{ - struct container *container = l_queue_peek_head(builder->containers); - size_t qlen = l_queue_length(builder->containers); - struct container *parent; - size_t start; - size_t siglen; - size_t offset; - - if (unlikely(qlen <= 1)) - return false; - - if (unlikely(container->type != DBUS_CONTAINER_TYPE_VARIANT)) - return false; - - l_queue_pop_head(builder->containers); - qlen -= 1; - parent = l_queue_peek_head(builder->containers); - - siglen = strlen(container->signature); - start = grow_body(builder, siglen + 1, 1); - memset(builder->body + start, 0, 1); - memcpy(builder->body + start + 1, container->signature, siglen); - - if (!grow_offsets(parent)) - return false; - - offset = builder->body_pos - parent->start; - parent->offsets[parent->offset_index++] = offset; - parent->variable_is_last = true; - - if (qlen == 1) - l_string_append_c(builder->signature, 'v'); - else if (parent->type != DBUS_CONTAINER_TYPE_ARRAY) - parent->sigindex += 1; - - container_free(container); - - return true; -} - -bool _gvariant_builder_enter_array(struct dbus_builder *builder, - const char *signature) -{ - size_t qlen = l_queue_length(builder->containers); - struct container *container = l_queue_peek_head(builder->containers); - size_t start; - int alignment; - - if (_gvariant_num_children(signature) != 1) - return false; - - if (qlen == 1) { - if (l_string_length(builder->signature) + - strlen(signature) + 1 > 255) - return false; - } else { - /* Verify Signatures Match */ - char expect[256]; - const char *start; - const char *end; - - start = container->signature + container->sigindex; - end = validate_next_type(start, &alignment); - - if (*start != 'a') - return false; - - memcpy(expect, start + 1, end - start - 1); - expect[end - start - 1] = '\0'; - - if (strcmp(expect, signature)) - return false; - } - - alignment = _gvariant_get_alignment(signature); - start = grow_body(builder, 0, alignment); - - container = container_new(DBUS_CONTAINER_TYPE_ARRAY, signature, start); - l_queue_push_head(builder->containers, container); - - return true; -} - -bool _gvariant_builder_leave_array(struct dbus_builder *builder) -{ - struct container *container = l_queue_peek_head(builder->containers); - size_t qlen = l_queue_length(builder->containers); - struct container *parent; - size_t offset; - - if (unlikely(qlen <= 1)) - return false; - - if (unlikely(container->type != DBUS_CONTAINER_TYPE_ARRAY)) - return false; - - l_queue_pop_head(builder->containers); - qlen -= 1; - parent = l_queue_peek_head(builder->containers); - - if (!_gvariant_is_fixed_size(container->signature)) - container_append_array_offsets(container, builder); - - if (!grow_offsets(parent)) - return false; - - offset = builder->body_pos - parent->start; - parent->offsets[parent->offset_index++] = offset; - parent->variable_is_last = true; - - if (qlen == 1) - l_string_append_printf(builder->signature, "a%s", - container->signature); - else if (parent->type != DBUS_CONTAINER_TYPE_ARRAY) - parent->sigindex += strlen(container->signature) + 1; - - container_free(container); - - return true; -} - -bool _gvariant_builder_append_basic(struct dbus_builder *builder, - char type, const void *value) -{ - struct container *container = l_queue_peek_head(builder->containers); - size_t start; - unsigned int alignment; - size_t len; - size_t offset; - - if (unlikely(!builder)) - return false; - - if (unlikely(!strchr(simple_types, type))) - return false; - - alignment = get_basic_alignment(type); - if (!alignment) - return false; - - if (l_queue_length(builder->containers) == 1) - l_string_append_c(builder->signature, type); - else if (container->signature[container->sigindex] != type) - return false; - - len = get_basic_fixed_size(type); - - if (len) { - start = grow_body(builder, len, alignment); - memcpy(builder->body + start, value, len); - container->variable_is_last = false; - - if (container->type != DBUS_CONTAINER_TYPE_ARRAY) - container->sigindex += 1; - - return true; - } - - if (!grow_offsets(container)) - return false; - - len = strlen(value) + 1; - start = grow_body(builder, len, alignment); - memcpy(builder->body + start, value, len); - - offset = builder->body_pos - container->start; - container->offsets[container->offset_index++] = offset; - container->variable_is_last = true; - - if (container->type != DBUS_CONTAINER_TYPE_ARRAY) - container->sigindex += 1; - - return true; -} - -bool _gvariant_builder_mark(struct dbus_builder *builder) -{ - struct container *container = l_queue_peek_head(builder->containers); - - builder->mark.container = container; - - if (l_queue_length(builder->containers) == 1) - builder->mark.sig_end = l_string_length(builder->signature); - else - builder->mark.sig_end = container->sigindex; - - builder->mark.body_pos = builder->body_pos; - builder->mark.offset_index = container->offset_index; - builder->mark.variable_is_last = container->variable_is_last; - - return true; -} - -bool _gvariant_builder_rewind(struct dbus_builder *builder) -{ - struct container *container; - - while ((container = l_queue_peek_head(builder->containers)) != - builder->mark.container) { - container_free(container); - l_queue_pop_head(builder->containers); - } - - builder->body_pos = builder->mark.body_pos; - container->offset_index = builder->mark.offset_index; - container->variable_is_last = builder->mark.variable_is_last; - - if (l_queue_length(builder->containers) == 1) - l_string_truncate(builder->signature, builder->mark.sig_end); - else - container->sigindex = builder->mark.sig_end; - - return true; -} - -char *_gvariant_builder_finish(struct dbus_builder *builder, - void **body, size_t *body_size) -{ - char *signature; - struct container *root; - uint8_t *variant_buf; - size_t size; - - if (unlikely(!builder)) - return NULL; - - if (unlikely(l_queue_length(builder->containers) != 1)) - return NULL; - - root = l_queue_peek_head(builder->containers); - - signature = l_string_unwrap(builder->signature); - builder->signature = NULL; - - if (_gvariant_is_fixed_size(signature)) { - int alignment = _gvariant_get_alignment(signature); - grow_body(builder, 0, alignment); - - /* Empty struct or "unit type" is encoded as a zero byte */ - if (signature[0] == '\0') { - size_t start = grow_body(builder, 1, 1); - - memset(builder->body + start, 0, 1); - } - } else - container_append_struct_offsets(root, builder); - - /* - * Make sure there's enough space after the body for the variant - * signature written here but not included in the body size and - * one framing offset value to be written in - * _gvariant_message_finalize. - */ - size = 3 + strlen(signature) + 8; - if (builder->body_pos + size > builder->body_size) - builder->body = l_realloc(builder->body, - builder->body_pos + size); - - variant_buf = builder->body + builder->body_pos; - *variant_buf++ = 0; - *variant_buf++ = '('; - variant_buf = mempcpy(variant_buf, signature, strlen(signature)); - *variant_buf++ = ')'; - - *body = builder->body; - *body_size = builder->body_pos; - builder->body = NULL; - builder->body_size = 0; - - return signature; -} - -/* - * Write the header's framing offset after the body variant which is the - * last piece of data in the message after the header, the padding and - * the builder has written the message body. - */ -size_t _gvariant_message_finalize(size_t header_end, - void *body, size_t body_size, - const char *signature) -{ - size_t offset_start; - size_t offset_size; - - offset_start = body_size + 3 + strlen(signature); - - offset_size = offset_length(align_len(header_end, 8) + offset_start, 1); - - write_word_le(body + offset_start, header_end, offset_size); - - return align_len(header_end, 8) + offset_start + offset_size; -} diff --git a/ell/hashmap.c b/ell/hashmap.c deleted file mode 100644 index 0d552e5..0000000 --- a/ell/hashmap.c +++ /dev/null @@ -1,653 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "util.h" -#include "hashmap.h" -#include "private.h" - -/** - * SECTION:hashmap - * @short_description: Hash table support - * - * Hash table support - */ - -#define NBUCKETS 127 - -struct entry { - void *key; - void *value; - struct entry *next; - unsigned int hash; -}; - -/** - * l_hashmap: - * - * Opague object representing the hash table. - */ -struct l_hashmap { - l_hashmap_hash_func_t hash_func; - l_hashmap_compare_func_t compare_func; - l_hashmap_key_new_func_t key_new_func; - l_hashmap_key_free_func_t key_free_func; - unsigned int entries; - struct entry buckets[NBUCKETS]; -}; - -static inline void *get_key_new(const struct l_hashmap *hashmap, - const void *key) -{ - if (hashmap->key_new_func) - return hashmap->key_new_func(key); - - return (void *)key; -} - -static inline void free_key(const struct l_hashmap *hashmap, void *key) -{ - if (hashmap->key_free_func) - hashmap->key_free_func(key); -} - -static inline unsigned int hash_superfast(const uint8_t *key, unsigned int len) -{ - /* - * Paul Hsieh (http://www.azillionmonkeys.com/qed/hash.html) - * used by WebCore (http://webkit.org/blog/8/hashtables-part-2/), - * EFL's eina, kmod and possible others. - */ - unsigned int tmp, hash = len, rem = len & 3; - - len /= 4; - - /* Main loop */ - for (; len > 0; len--) { - hash += l_get_u16(key); - tmp = (l_get_u16(key + 2) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - key += 4; - hash += hash >> 11; - } - - /* Handle end cases */ - switch (rem) { - case 3: - hash += l_get_u16(key); - hash ^= hash << 16; - hash ^= key[2] << 18; - hash += hash >> 11; - break; - - case 2: - hash += l_get_u16(key); - hash ^= hash << 11; - hash += hash >> 17; - break; - - case 1: - hash += *key; - hash ^= hash << 10; - hash += hash >> 1; - break; - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; -} - -static unsigned int direct_hash_func(const void *p) -{ - return L_PTR_TO_UINT(p); -} - -static int direct_compare_func(const void *a, const void *b) -{ - return a < b ? -1 : (a > b ? 1 : 0); -} - -/** - * l_hashmap_new: - * - * Create a new hash table. The keys are managed as pointers, that is, - * the pointer value is hashed and looked up. - * - * No error handling is needed since. In case of real memory allocation - * problems abort() will be called. - * - * See also l_hashmap_string_new(). - * - * Returns: a newly allocated #l_hashmap object - **/ -LIB_EXPORT struct l_hashmap *l_hashmap_new(void) -{ - struct l_hashmap *hashmap; - - hashmap = l_new(struct l_hashmap, 1); - - hashmap->hash_func = direct_hash_func; - hashmap->compare_func = direct_compare_func; - hashmap->entries = 0; - - return hashmap; -} - -LIB_EXPORT unsigned int l_str_hash(const void *p) -{ - const char *s = p; - size_t len = strlen(s); - - return hash_superfast((const uint8_t *)s, len); -} - -/** - * l_hashmap_string_new: - * - * Create a new hash table. The keys are considered strings and are - * copied. - * - * No error handling is needed since. In case of real memory allocation - * problems abort() will be called. - * - * See also l_hashmap_new(). - * - * Returns: a newly allocated #l_hashmap object - **/ -LIB_EXPORT struct l_hashmap *l_hashmap_string_new(void) -{ - struct l_hashmap *hashmap; - - hashmap = l_new(struct l_hashmap, 1); - - hashmap->hash_func = l_str_hash; - hashmap->compare_func = (l_hashmap_compare_func_t) strcmp; - hashmap->key_new_func = (l_hashmap_key_new_func_t) l_strdup; - hashmap->key_free_func = l_free; - hashmap->entries = 0; - - return hashmap; -} - -/** - * l_hashmap_set_hash_function: - * @hashmap: hash table object - * @func: Key hashing function - * - * Sets the hashing function to be used by this object. - * - * This function can only be called when the @hashmap is empty. - * - * Returns: #true when the hashing function could be updated successfully, - * and #false otherwise. - **/ -LIB_EXPORT bool l_hashmap_set_hash_function(struct l_hashmap *hashmap, - l_hashmap_hash_func_t func) -{ - if (unlikely(!hashmap)) - return false; - - if (hashmap->entries != 0) - return false; - - hashmap->hash_func = func; - - return true; -} - -/** - * l_hashmap_set_compare_function: - * @hashmap: hash table object - * @func: Key compare function - * - * Sets the key comparison function to be used by this object. - * - * This function can only be called when the @hashmap is empty. - * - * Returns: #true when the comparison function could be updated successfully, - * and #false otherwise. - **/ -LIB_EXPORT bool l_hashmap_set_compare_function(struct l_hashmap *hashmap, - l_hashmap_compare_func_t func) -{ - if (unlikely(!hashmap)) - return false; - - if (hashmap->entries != 0) - return false; - - hashmap->compare_func = func; - - return true; -} - -/** - * l_hashmap_set_key_copy_function: - * @hashmap: hash table object - * @func: Key duplication function - * - * Sets the key duplication function to be used by this object. If the - * function is NULL, then the keys are assigned directly. - * - * This function can only be called when the @hashmap is empty. - * - * Returns: #true when the key copy function could be updated successfully, - * and #false otherwise. - **/ -LIB_EXPORT bool l_hashmap_set_key_copy_function(struct l_hashmap *hashmap, - l_hashmap_key_new_func_t func) -{ - if (unlikely(!hashmap)) - return false; - - if (hashmap->entries != 0) - return false; - - hashmap->key_new_func = func; - - return true; -} - -/** - * l_hashmap_set_key_free_function: - * @hashmap: hash table object - * @func: Key destructor function - * - * Sets the key destructor function to be used by this object. This function - * should undo the result of the function specified in - * l_hashmap_set_key_copy_function(). This function can be NULL, in which - * case no destructor is called. - * - * This function can only be called when the @hashmap is empty. - * - * Returns: #true when the key free function could be updated successfully, - * and #false otherwise. - **/ -LIB_EXPORT bool l_hashmap_set_key_free_function(struct l_hashmap *hashmap, - l_hashmap_key_free_func_t func) -{ - if (unlikely(!hashmap)) - return false; - - if (hashmap->entries != 0) - return false; - - hashmap->key_free_func = func; - - return true; -} - -/** - * l_hashmap_destroy: - * @hashmap: hash table object - * @destroy: destroy function - * - * Free hash table and call @destory on all remaining entries. - * - * NOTE: While the destroy is in progress, the hashmap is assumed to be - * invariant. The behavior of adding or removing entries while a destroy - * operation is in progress is undefined. - **/ -LIB_EXPORT void l_hashmap_destroy(struct l_hashmap *hashmap, - l_hashmap_destroy_func_t destroy) -{ - unsigned int i; - - if (unlikely(!hashmap)) - return; - - for (i = 0; i < NBUCKETS; i++) { - struct entry *entry, *next, *head = &hashmap->buckets[i]; - - if (!head->next) - continue; - - for (entry = head;; entry = next) { - if (destroy) - destroy(entry->value); - - free_key(hashmap, entry->key); - - next = entry->next; - - if (entry != head) - l_free(entry); - - if (next == head) - break; - } - } - - l_free(hashmap); -} - -/** - * l_hashmap_insert: - * @hashmap: hash table object - * @key: key pointer - * @value: value pointer - * - * Insert new @value entry with @key. - * - * Returns: #true when value has been added and #false in case of failure - **/ -LIB_EXPORT bool l_hashmap_insert(struct l_hashmap *hashmap, - const void *key, void *value) -{ - struct entry *entry, *head; - unsigned int hash; - void *key_new; - - if (unlikely(!hashmap)) - return false; - - key_new = get_key_new(hashmap, key); - hash = hashmap->hash_func(key_new); - head = &hashmap->buckets[hash % NBUCKETS]; - - if (!head->next) { - head->key = key_new; - head->value = value; - head->hash = hash; - head->next = head; - goto done; - } - - entry = l_new(struct entry, 1); - entry->key = key_new; - entry->value = value; - entry->hash = hash; - entry->next = head; - - while (head->next != entry->next) - head = head->next; - - head->next = entry; - -done: - hashmap->entries++; - - return true; -} - -/** - * l_hashmap_remove: - * @hashmap: hash table object - * @key: key pointer - * - * Remove entry for @key. - * - * Returns: value pointer of the removed entry or #NULL in case of failure - **/ -LIB_EXPORT void *l_hashmap_remove(struct l_hashmap *hashmap, const void *key) -{ - struct entry *entry, *head, *prev; - unsigned int hash; - - if (unlikely(!hashmap)) - return NULL; - - hash = hashmap->hash_func(key); - head = &hashmap->buckets[hash % NBUCKETS]; - - if (!head->next) - return NULL; - - for (entry = head, prev = NULL;; prev = entry, entry = entry->next) { - void *value; - - if (entry->hash != hash) - goto next; - - if (hashmap->compare_func(key, entry->key)) - goto next; - - value = entry->value; - - if (entry == head) { - if (entry->next == head) { - free_key(hashmap, entry->key); - head->key = NULL; - head->value = NULL; - head->hash = 0; - head->next = NULL; - } else { - entry = entry->next; - free_key(hashmap, head->key); - head->key = entry->key; - head->value = entry->value; - head->hash = entry->hash; - head->next = entry->next; - l_free(entry); - } - } else { - prev->next = entry->next; - free_key(hashmap, entry->key); - l_free(entry); - } - - hashmap->entries--; - - return value; - -next: - if (entry->next == head) - break; - } - - return NULL; -} - -/** - * l_hashmap_lookup: - * @hashmap: hash table object - * @key: key pointer - * - * Lookup entry for @key. - * - * Returns: value pointer for @key or #NULL in case of failure - **/ -LIB_EXPORT void *l_hashmap_lookup(struct l_hashmap *hashmap, const void *key) -{ - struct entry *entry, *head; - unsigned int hash; - - if (unlikely(!hashmap)) - return NULL; - - hash = hashmap->hash_func(key); - head = &hashmap->buckets[hash % NBUCKETS]; - - if (!head->next) - return NULL; - - for (entry = head;; entry = entry->next) { - if (entry->hash == hash && - !hashmap->compare_func(key, entry->key)) - return entry->value; - - if (entry->next == head) - break; - } - - return NULL; -} - -/** - * l_hashmap_foreach: - * @hashmap: hash table object - * @function: callback function - * @user_data: user data given to callback function - * - * Call @function for every entry in @hashmap. - * - * NOTE: While the foreach is in progress, the hashmap is assumed to be - * invariant. The behavior of adding or removing entries while a foreach - * operation is in progress is undefined. - **/ -LIB_EXPORT void l_hashmap_foreach(struct l_hashmap *hashmap, - l_hashmap_foreach_func_t function, void *user_data) -{ - unsigned int i; - - if (unlikely(!hashmap || !function)) - return; - - for (i = 0; i < NBUCKETS; i++) { - struct entry *entry, *head = &hashmap->buckets[i]; - - if (!head->next) - continue; - - for (entry = head;; entry = entry->next) { - function(entry->key, entry->value, user_data); - - if (entry->next == head) - break; - } - } -} - -/** - * l_hashmap_foreach_remove: - * @hashmap: hash table object - * @function: callback function - * @user_data: user data given to callback function - * - * Call @function for every entry in @hashmap. If the @function returns - * true, then the object will be removed from the hashmap. - * - * NOTE: While the foreach is in progress, the hashmap is assumed to be - * invariant. The behavior of adding or removing entries while a foreach - * operation is in progress is undefined. - * - * Returns: Number of entries removed. - **/ -LIB_EXPORT unsigned int l_hashmap_foreach_remove(struct l_hashmap *hashmap, - l_hashmap_remove_func_t function, - void *user_data) -{ - unsigned int i; - unsigned int nremoved = 0; - - if (unlikely(!hashmap || !function)) - return 0; - - for (i = 0; i < NBUCKETS; i++) { - struct entry *head = &hashmap->buckets[i]; - struct entry *entry; - struct entry *prev; - bool remove; - - if (head->next == NULL) - continue; - - entry = head; - prev = NULL; - - while (true) { - remove = function(entry->key, entry->value, user_data); - - if (!remove) - goto next; - - nremoved += 1; - hashmap->entries -= 1; - - if (entry == head) { - if (entry->next == head) { - free_key(hashmap, entry->key); - head->key = NULL; - head->value = NULL; - head->hash = 0; - head->next = NULL; - break; - } else { - entry = entry->next; - free_key(hashmap, head->key); - head->key = entry->key; - head->value = entry->value; - head->hash = entry->hash; - head->next = entry->next; - l_free(entry); - entry = head; - continue; - } - } else { - prev->next = entry->next; - free_key(hashmap, entry->key); - l_free(entry); - entry = prev->next; - if (entry == head) - break; - continue; - } - -next: - if (entry->next == head) - break; - - prev = entry; - entry = entry->next; - } - } - - return nremoved; -} - -/** - * l_hashmap_size: - * @hashmap: hash table object - * - * Returns: entries in the hash table - **/ -LIB_EXPORT unsigned int l_hashmap_size(struct l_hashmap *hashmap) -{ - if (unlikely(!hashmap)) - return 0; - - return hashmap->entries; -} - -/** - * l_hashmap_isempty: - * @hashmap: hash table object - * - * Returns: #true if hash table is empty and #false if not - **/ -LIB_EXPORT bool l_hashmap_isempty(struct l_hashmap *hashmap) -{ - if (unlikely(!hashmap)) - return true; - - return hashmap->entries == 0; -} diff --git a/ell/hashmap.h b/ell/hashmap.h deleted file mode 100644 index 3d23c7e..0000000 --- a/ell/hashmap.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_HASHMAP_H -#define __ELL_HASHMAP_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*l_hashmap_foreach_func_t) (const void *key, void *value, - void *user_data); -typedef void (*l_hashmap_destroy_func_t) (void *value); -typedef unsigned int (*l_hashmap_hash_func_t) (const void *p); -typedef int (*l_hashmap_compare_func_t) (const void *a, const void *b); -typedef void *(*l_hashmap_key_new_func_t) (const void *p); -typedef void (*l_hashmap_key_free_func_t) (void *p); -typedef bool (*l_hashmap_remove_func_t)(const void *key, void *value, - void *user_data); - -struct l_hashmap; - -unsigned int l_str_hash(const void *p); - -struct l_hashmap *l_hashmap_new(void); -struct l_hashmap *l_hashmap_string_new(void); - -bool l_hashmap_set_hash_function(struct l_hashmap *hashmap, - l_hashmap_hash_func_t func); -bool l_hashmap_set_compare_function(struct l_hashmap *hashmap, - l_hashmap_compare_func_t func); -bool l_hashmap_set_key_copy_function(struct l_hashmap *hashmap, - l_hashmap_key_new_func_t func); -bool l_hashmap_set_key_free_function(struct l_hashmap *hashmap, - l_hashmap_key_free_func_t func); - -void l_hashmap_destroy(struct l_hashmap *hashmap, - l_hashmap_destroy_func_t destroy); - -bool l_hashmap_insert(struct l_hashmap *hashmap, - const void *key, void *value); -void *l_hashmap_remove(struct l_hashmap *hashmap, const void *key); -void *l_hashmap_lookup(struct l_hashmap *hashmap, const void *key); - -void l_hashmap_foreach(struct l_hashmap *hashmap, - l_hashmap_foreach_func_t function, void *user_data); -unsigned int l_hashmap_foreach_remove(struct l_hashmap *hashmap, - l_hashmap_remove_func_t function, void *user_data); - -unsigned int l_hashmap_size(struct l_hashmap *hashmap); -bool l_hashmap_isempty(struct l_hashmap *hashmap); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_HASHMAP_H */ diff --git a/ell/hwdb.c b/ell/hwdb.c deleted file mode 100644 index 0d5f95a..0000000 --- a/ell/hwdb.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "hwdb.h" -#include "private.h" - -static const char trie_sig[8] = { 'K', 'S', 'L', 'P', 'H', 'H', 'R', 'H' }; - -struct trie_header { - uint8_t signature[8]; /* Signature */ - uint64_t version; /* Version of creator tool */ - uint64_t file_size; /* Size of complete file */ - uint64_t header_size; /* Size of header structure */ - uint64_t node_size; /* Size of node structure */ - uint64_t child_size; /* Size of child structure */ - uint64_t entry_size; /* Size of entry structure */ - uint64_t root_offset; /* Location of root node structure */ - uint64_t nodes_size; /* Size of the nodes section */ - uint64_t strings_size; /* Size of the strings section */ - - /* followed by nodes_size nodes data */ - /* followed by strings_size strings data */ -} __attribute__ ((packed)); - -struct trie_node { - uint64_t prefix_offset; /* Location of prefix string */ - uint8_t child_count; /* Number of child structures */ - uint8_t padding[7]; - uint64_t entry_count; /* Number of entry structures */ - - /* followed by child_count child structures */ - /* followed by entry_count entry structures */ -} __attribute__ ((packed)); - -struct trie_child { - uint8_t c; /* Prefix character of child node */ - uint8_t padding[7]; - uint64_t child_offset; /* Location of child node structure */ -} __attribute__ ((packed)); - -struct trie_entry { - uint64_t key_offset; /* Location of key string */ - uint64_t value_offset; /* Location of value string */ -} __attribute__ ((packed)); - -struct l_hwdb { - int ref_count; - int fd; - time_t mtime; - size_t size; - void *addr; - uint64_t root; -}; - -LIB_EXPORT struct l_hwdb *l_hwdb_new(const char *pathname) -{ - struct trie_header *hdr; - struct l_hwdb *hwdb; - struct stat st; - void *addr; - size_t size; - int fd; - - if (!pathname) - return NULL; - - fd = open(pathname, O_RDONLY | O_CLOEXEC); - if (fd < 0) - return NULL; - - if (fstat(fd, &st) < 0) { - close(fd); - return NULL; - } - - size = st.st_size; - if (size < sizeof(struct trie_header)) { - close(fd); - return NULL; - } - - addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - if (addr == MAP_FAILED) { - close(fd); - return NULL; - } - - hdr = addr; - if (memcmp(hdr->signature, trie_sig, sizeof(trie_sig))) - goto failed; - - if (L_LE64_TO_CPU(hdr->file_size) != size) - goto failed; - - if (L_LE64_TO_CPU(hdr->header_size) != sizeof(struct trie_header)) - goto failed; - - if (L_LE64_TO_CPU(hdr->node_size) != sizeof(struct trie_node)) - goto failed; - - if (L_LE64_TO_CPU(hdr->child_size) != sizeof(struct trie_child)) - goto failed; - - if (L_LE64_TO_CPU(hdr->entry_size) < sizeof(struct trie_entry)) - goto failed; - - if (L_LE64_TO_CPU(hdr->header_size) + L_LE64_TO_CPU(hdr->nodes_size) + - L_LE64_TO_CPU(hdr->strings_size) != size) - goto failed; - - hwdb = l_new(struct l_hwdb, 1); - - hwdb->fd = fd; - hwdb->mtime = st.st_mtime; - hwdb->size = size; - hwdb->addr = addr; - hwdb->root = L_LE64_TO_CPU(hdr->root_offset); - - return l_hwdb_ref(hwdb); - -failed: - munmap(addr, st.st_size); - close(fd); - return NULL; -} - -LIB_EXPORT struct l_hwdb *l_hwdb_new_default(void) -{ - struct l_hwdb *db = NULL; - size_t i; - const char * const paths[] = {"/etc/udev/hwdb.bin", - "/usr/lib/udev/hwdb.bin", - "/lib/udev/hwdb.bin"}; - - for (i = 0; !db && i < L_ARRAY_SIZE(paths); i++) - db = l_hwdb_new(paths[i]); - - return db; -} - -LIB_EXPORT struct l_hwdb *l_hwdb_ref(struct l_hwdb *hwdb) -{ - if (!hwdb) - return NULL; - - __sync_fetch_and_add(&hwdb->ref_count, 1); - - return hwdb; -} - -LIB_EXPORT void l_hwdb_unref(struct l_hwdb *hwdb) -{ - if (!hwdb) - return; - - if (__sync_sub_and_fetch(&hwdb->ref_count, 1)) - return; - - munmap(hwdb->addr, hwdb->size); - - close(hwdb->fd); - - l_free(hwdb); -} - -static void trie_fnmatch(const void *addr, uint64_t offset, const char *prefix, - const char *string, - struct l_hwdb_entry **entries) -{ - const struct trie_node *node = addr + offset; - const void *addr_ptr = addr + offset + sizeof(*node); - const char *prefix_str = addr + L_LE64_TO_CPU(node->prefix_offset); - uint64_t child_count = L_LE64_TO_CPU(node->child_count); - uint64_t entry_count = L_LE64_TO_CPU(node->entry_count); - uint64_t i; - size_t scratch_len; - char *scratch_buf; - - scratch_len = strlen(prefix) + strlen(prefix_str); - scratch_buf = alloca(scratch_len + 2); - sprintf(scratch_buf, "%s%s", prefix, prefix_str); - scratch_buf[scratch_len + 1] = '\0'; - - /* - * Only incur the cost of this fnmatch() if there are children - * to visit. In practice, nodes have either entries or children - * so fnmatch() will only be called once per node. - */ - if (child_count) { - scratch_buf[scratch_len] = '*'; - - if (fnmatch(scratch_buf, string, 0) == FNM_NOMATCH) - child_count = 0; - } - - for (i = 0; i < child_count; i++) { - const struct trie_child *child = addr_ptr; - - scratch_buf[scratch_len] = child->c; - - trie_fnmatch(addr, L_LE64_TO_CPU(child->child_offset), - scratch_buf, string, entries); - - addr_ptr += sizeof(*child); - } - - if (!entry_count) - return; - - scratch_buf[scratch_len] = '\0'; - - if (fnmatch(scratch_buf, string, 0)) - return; - - for (i = 0; i < entry_count; i++) { - const struct trie_entry *entry = addr_ptr; - const char *key_str = addr + L_LE64_TO_CPU(entry->key_offset); - const char *val_str = addr + L_LE64_TO_CPU(entry->value_offset); - struct l_hwdb_entry *result; - - if (key_str[0] == ' ') { - result = l_new(struct l_hwdb_entry, 1); - - result->key = key_str + 1; - result->value = val_str; - result->next = (*entries); - *entries = result; - } - - addr_ptr += sizeof(*entry); - } -} - -LIB_EXPORT struct l_hwdb_entry *l_hwdb_lookup(struct l_hwdb *hwdb, - const char *format, ...) -{ - struct l_hwdb_entry *entries = NULL; - va_list args; - - va_start(args, format); - entries = l_hwdb_lookup_valist(hwdb, format, args); - va_end(args); - - return entries; -} - -LIB_EXPORT struct l_hwdb_entry *l_hwdb_lookup_valist(struct l_hwdb *hwdb, - const char *format, va_list args) -{ - struct l_hwdb_entry *entries = NULL; - char *modalias; - int len; - - if (!hwdb || !format) - return NULL; - - len = vasprintf(&modalias, format, args); - if (len < 0) - return NULL; - - trie_fnmatch(hwdb->addr, hwdb->root, "", modalias, &entries); - - free(modalias); - - return entries; -} - -LIB_EXPORT void l_hwdb_lookup_free(struct l_hwdb_entry *entries) -{ - while (entries) { - struct l_hwdb_entry *entry = entries; - - entries = entries->next; - - l_free(entry); - } -} - -static void foreach_node(const void *addr, uint64_t offset, const char *prefix, - l_hwdb_foreach_func_t func, void *user_data) -{ - const struct trie_node *node = addr + offset; - const void *addr_ptr = addr + offset + sizeof(*node); - const char *prefix_str = addr + L_LE64_TO_CPU(node->prefix_offset); - uint64_t child_count = L_LE64_TO_CPU(node->child_count); - uint64_t entry_count = L_LE64_TO_CPU(node->entry_count); - uint64_t i; - size_t scratch_len; - char *scratch_buf; - struct l_hwdb_entry *entries = NULL; - - scratch_len = strlen(prefix) + strlen(prefix_str); - scratch_buf = alloca(scratch_len + 2); - sprintf(scratch_buf, "%s%s", prefix, prefix_str); - scratch_buf[scratch_len + 1] = '\0'; - - for (i = 0; i < child_count; i++) { - const struct trie_child *child = addr_ptr; - - scratch_buf[scratch_len] = child->c; - - foreach_node(addr, L_LE64_TO_CPU(child->child_offset), - scratch_buf, func, user_data); - - addr_ptr += sizeof(*child); - } - - if (!entry_count) - return; - - scratch_buf[scratch_len] = '\0'; - - for (i = 0; i < entry_count; i++) { - const struct trie_entry *entry = addr_ptr; - const char *key_str = addr + L_LE64_TO_CPU(entry->key_offset); - const char *val_str = addr + L_LE64_TO_CPU(entry->value_offset); - struct l_hwdb_entry *result; - - if (key_str[0] == ' ') { - result = l_new(struct l_hwdb_entry, 1); - - result->key = key_str + 1; - result->value = val_str; - result->next = entries; - entries = result; - } - - addr_ptr += sizeof(*entry); - } - - func(scratch_buf, entries, user_data); - - l_hwdb_lookup_free(entries); -} - -LIB_EXPORT bool l_hwdb_foreach(struct l_hwdb *hwdb, l_hwdb_foreach_func_t func, - void *user_data) -{ - if (!hwdb || !func) - return false; - - foreach_node(hwdb->addr, hwdb->root, "", func, user_data); - - return true; -} diff --git a/ell/hwdb.h b/ell/hwdb.h deleted file mode 100644 index f37dac7..0000000 --- a/ell/hwdb.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_HWDB_H -#define __ELL_HWDB_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_hwdb; - -struct l_hwdb *l_hwdb_new(const char *pathname); -struct l_hwdb *l_hwdb_new_default(void); - -struct l_hwdb *l_hwdb_ref(struct l_hwdb *hwdb); -void l_hwdb_unref(struct l_hwdb *hwdb); - -struct l_hwdb_entry { - const char *key; - const char *value; - struct l_hwdb_entry *next; -}; - -struct l_hwdb_entry *l_hwdb_lookup(struct l_hwdb *hwdb, const char *format, ...) - __attribute__((format(printf, 2, 3))); -struct l_hwdb_entry *l_hwdb_lookup_valist(struct l_hwdb *hwdb, - const char *format, va_list args); -void l_hwdb_lookup_free(struct l_hwdb_entry *entries); - -typedef void (*l_hwdb_foreach_func_t)(const char *modalias, - struct l_hwdb_entry *entries, - void *user_data); - -bool l_hwdb_foreach(struct l_hwdb *hwdb, l_hwdb_foreach_func_t func, - void *user_data); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_HWDB_H */ diff --git a/ell/idle.c b/ell/idle.c deleted file mode 100644 index 5c66280..0000000 --- a/ell/idle.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "util.h" -#include "idle.h" -#include "private.h" - -/** - * SECTION:idle - * @short_description: Idle processing support - * - * Idle processing support - */ - -/** - * l_idle: - * - * Opague object representing the idle time event. - */ -struct l_idle { - union { - l_idle_notify_cb_t callback; - l_idle_oneshot_cb_t oneshot; - }; - - l_idle_destroy_cb_t destroy; - void *user_data; - int id; -}; - -static void idle_destroy(void *user_data) -{ - struct l_idle *idle = user_data; - - if (idle->destroy) - idle->destroy(idle->user_data); - - l_free(idle); -} - -static void idle_callback(void *user_data) -{ - struct l_idle *idle = user_data; - - if (idle->callback) - idle->callback(idle, idle->user_data); -} - -static void oneshot_callback(void *user_data) -{ - struct l_idle *idle = user_data; - - if (idle->oneshot) - idle->oneshot(idle->user_data); - - idle_remove(idle->id); -} - -/** - * l_idle_create: - * @callback: idle callback function - * @user_data: user data provided to idle callback function - * @destroy: destroy function for user data - * - * Create a new idle event processing object. - * - * The idle callback will be called until canceled using l_idle_remove(). - * - * Returns: a newly allocated #l_idle object - **/ -LIB_EXPORT struct l_idle *l_idle_create(l_idle_notify_cb_t callback, - void *user_data, l_idle_destroy_cb_t destroy) -{ - struct l_idle *idle; - - if (unlikely(!callback)) - return NULL; - - idle = l_new(struct l_idle, 1); - - idle->callback = callback; - idle->destroy = destroy; - idle->user_data = user_data; - - idle->id = idle_add(idle_callback, idle, 0, idle_destroy); - if (idle->id < 0) { - l_free(idle); - return NULL; - } - - return idle; -} - -/** - * l_idle_oneshot: - * @callback: idle callback function - * @user_data: user data provided to idle callback function - * @destroy: destroy function for user data - * - * Create a new idle event processing object. The callback will be called - * only once at which point the object will be destroyed. - * - * Returns: true if the oneshot idle object could be created successfully. - **/ -LIB_EXPORT bool l_idle_oneshot(l_idle_oneshot_cb_t callback, void *user_data, - l_idle_destroy_cb_t destroy) -{ - struct l_idle *idle; - - if (unlikely(!callback)) - return NULL; - - idle = l_new(struct l_idle, 1); - - idle->oneshot = callback; - idle->destroy = destroy; - idle->user_data = user_data; - - idle->id = idle_add(oneshot_callback, idle, - IDLE_FLAG_NO_WARN_DANGLING, idle_destroy); - if (idle->id < 0) { - l_free(idle); - return false; - } - - return true; -} -/** - * l_idle_remove: - * @idle: idle object - * - * Remove idle event processing object. - **/ -LIB_EXPORT void l_idle_remove(struct l_idle *idle) -{ - if (unlikely(!idle)) - return; - - idle_remove(idle->id); -} diff --git a/ell/idle.h b/ell/idle.h deleted file mode 100644 index 19ae4d3..0000000 --- a/ell/idle.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_IDLE_H -#define __ELL_IDLE_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_idle; - -typedef void (*l_idle_notify_cb_t) (struct l_idle *idle, void *user_data); -typedef void (*l_idle_oneshot_cb_t) (void *user_data); -typedef void (*l_idle_destroy_cb_t) (void *user_data); - -struct l_idle *l_idle_create(l_idle_notify_cb_t callback, - void *user_data, l_idle_destroy_cb_t destroy); -void l_idle_remove(struct l_idle *idle); - -bool l_idle_oneshot(l_idle_oneshot_cb_t callback, void *user_data, - l_idle_destroy_cb_t destroy); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_IDLE_H */ diff --git a/ell/io.c b/ell/io.c deleted file mode 100644 index 878060c..0000000 --- a/ell/io.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "util.h" -#include "io.h" -#include "private.h" - -/** - * SECTION:io - * @short_description: IO support - * - * IO support - */ - -/** - * l_io: - * - * Opague object representing the IO. - */ -struct l_io { - int fd; - uint32_t events; - bool close_on_destroy; - l_io_read_cb_t read_handler; - l_io_destroy_cb_t read_destroy; - void *read_data; - l_io_write_cb_t write_handler; - l_io_destroy_cb_t write_destroy; - void *write_data; - l_io_disconnect_cb_t disconnect_handler; - l_io_destroy_cb_t disconnect_destroy; - void *disconnect_data; - l_io_debug_cb_t debug_handler; - l_io_destroy_cb_t debug_destroy; - void *debug_data; -}; - -static void io_cleanup(void *user_data) -{ - struct l_io *io = user_data; - - l_util_debug(io->debug_handler, io->debug_data, "cleanup <%p>", io); - - if (io->write_destroy) - io->write_destroy(io->write_data); - - io->write_handler = NULL; - io->write_data = NULL; - - if (io->read_destroy) - io->read_destroy(io->read_data); - - io->read_handler = NULL; - io->read_data = NULL; - - if (io->close_on_destroy) - close(io->fd); - - io->fd = -1; -} - -static void io_closed(struct l_io *io) -{ - /* - * Save off copies of disconnect_handler, disconnect_destroy - * and disconnect_data in case the handler calls io_destroy - */ - l_io_disconnect_cb_t handler = io->disconnect_handler; - l_io_destroy_cb_t destroy = io->disconnect_destroy; - void *disconnect_data = io->disconnect_data; - - io->disconnect_handler = NULL; - io->disconnect_destroy = NULL; - io->disconnect_data = NULL; - - if (handler) - handler(io, disconnect_data); - - if (destroy) - destroy(disconnect_data); -} - -static void io_callback(int fd, uint32_t events, void *user_data) -{ - struct l_io *io = user_data; - - if (unlikely(events & (EPOLLERR | EPOLLHUP))) { - l_util_debug(io->debug_handler, io->debug_data, - "disconnect event <%p>", io); - watch_remove(io->fd); - io_closed(io); - return; - } - - if ((events & EPOLLIN) && io->read_handler) { - l_util_debug(io->debug_handler, io->debug_data, - "read event <%p>", io); - - if (!io->read_handler(io, io->read_data)) { - if (io->read_destroy) - io->read_destroy(io->read_data); - - io->read_handler = NULL; - io->read_destroy = NULL; - io->read_data = NULL; - - io->events &= ~EPOLLIN; - - if (watch_modify(io->fd, io->events, false) == -EBADF) { - io->close_on_destroy = false; - watch_clear(io->fd); - io_closed(io); - return; - } - } - } - - if ((events & EPOLLOUT) && io->write_handler) { - l_util_debug(io->debug_handler, io->debug_data, - "write event <%p>", io); - - if (!io->write_handler(io, io->write_data)) { - if (io->write_destroy) - io->write_destroy(io->write_data); - - io->write_handler = NULL; - io->write_destroy = NULL; - io->write_data = NULL; - - io->events &= ~EPOLLOUT; - - if (watch_modify(io->fd, io->events, false) == -EBADF) { - io->close_on_destroy = false; - watch_clear(io->fd); - io_closed(io); - return; - } - } - } -} - -/** - * l_io_new: - * @fd: file descriptor - * - * Create new IO handling for a given file descriptor. - * - * Returns: a newly allocated #l_io object - **/ -LIB_EXPORT struct l_io *l_io_new(int fd) -{ - struct l_io *io; - int err; - - if (unlikely(fd < 0)) - return NULL; - - io = l_new(struct l_io, 1); - - io->fd = fd; - io->events = EPOLLHUP | EPOLLERR; - io->close_on_destroy = false; - - err = watch_add(io->fd, io->events, io_callback, io, io_cleanup); - if (err) { - l_free(io); - return NULL; - } - - return io; -} - -/** - * l_io_destroy: - * @io: IO object - * - * Free IO object and close file descriptor (if enabled). - **/ -LIB_EXPORT void l_io_destroy(struct l_io *io) -{ - if (unlikely(!io)) - return; - - if (io->fd != -1) - watch_remove(io->fd); - - io_closed(io); - - if (io->debug_destroy) - io->debug_destroy(io->debug_data); - - l_free(io); -} - -/** - * l_io_get_fd: - * @io: IO object - * - * Returns: file descriptor associated with @io - **/ -LIB_EXPORT int l_io_get_fd(struct l_io *io) -{ - if (unlikely(!io)) - return -1; - - return io->fd; -} - -/** - * l_io_set_close_on_destroy: - * @io: IO object - * @do_close: setting for destroy handling - * - * Set the automatic closing of the file descriptor when destroying @io. - * - * Returns: #true on success and #false on failure - **/ -LIB_EXPORT bool l_io_set_close_on_destroy(struct l_io *io, bool do_close) -{ - if (unlikely(!io)) - return false; - - io->close_on_destroy = do_close; - - return true; -} - -/** - * l_io_set_read_handler: - * @io: IO object - * @callback: read handler callback function - * @user_data: user data provided to read handler callback function - * @destroy: destroy function for user data - * - * Set read function. - * - * Returns: #true on success and #false on failure - **/ -LIB_EXPORT bool l_io_set_read_handler(struct l_io *io, l_io_read_cb_t callback, - void *user_data, l_io_destroy_cb_t destroy) -{ - uint32_t events; - int err; - - if (unlikely(!io || io->fd < 0)) - return false; - - l_util_debug(io->debug_handler, io->debug_data, - "set read handler <%p>", io); - - if (io->read_destroy) - io->read_destroy(io->read_data); - - if (callback) - events = io->events | EPOLLIN; - else - events = io->events & ~EPOLLIN; - - io->read_handler = callback; - io->read_destroy = destroy; - io->read_data = user_data; - - if (events == io->events) - return true; - - err = watch_modify(io->fd, events, false); - if (err) - return false; - - io->events = events; - - return true; -} - -/** - * l_io_set_write_handler: - * @io: IO object - * @callback: write handler callback function - * @user_data: user data provided to write handler callback function - * @destroy: destroy function for user data - * - * Set write function. - * - * Returns: #true on success and #false on failure - **/ -LIB_EXPORT bool l_io_set_write_handler(struct l_io *io, l_io_write_cb_t callback, - void *user_data, l_io_destroy_cb_t destroy) -{ - uint32_t events; - int err; - - if (unlikely(!io || io->fd < 0)) - return false; - - l_util_debug(io->debug_handler, io->debug_data, - "set write handler <%p>", io); - - if (io->write_handler == callback && io->write_destroy == destroy && - io->write_data == user_data) - return true; - - if (io->write_destroy) - io->write_destroy(io->write_data); - - if (callback) - events = io->events | EPOLLOUT; - else - events = io->events & ~EPOLLOUT; - - io->write_handler = callback; - io->write_destroy = destroy; - io->write_data = user_data; - - if (events == io->events) - return true; - - err = watch_modify(io->fd, events, false); - if (err) - return false; - - io->events = events; - - return true; -} - -/** - * l_io_set_disconnect_handler: - * @io: IO object - * @callback: disconnect handler callback function - * @user_data: user data provided to disconnect handler callback function - * @destroy: destroy function for user data - * - * Set disconnect function. - * - * Returns: #true on success and #false on failure - **/ -LIB_EXPORT bool l_io_set_disconnect_handler(struct l_io *io, - l_io_disconnect_cb_t callback, - void *user_data, l_io_destroy_cb_t destroy) -{ - if (unlikely(!io || io->fd < 0)) - return false; - - l_util_debug(io->debug_handler, io->debug_data, - "set disconnect handler <%p>", io); - - if (io->disconnect_destroy) - io->disconnect_destroy(io->disconnect_data); - - io->disconnect_handler = callback; - io->disconnect_destroy = destroy; - io->disconnect_data = user_data; - - return true; -} - -/** - * l_io_set_debug: - * @io: IO object - * @callback: debug callback function - * @user_data: user data provided to debug callback function - * @destroy: destroy function for user data - * - * Set debug function. - * - * Returns: #true on success and #false on failure - **/ -LIB_EXPORT bool l_io_set_debug(struct l_io *io, l_io_debug_cb_t callback, - void *user_data, l_io_destroy_cb_t destroy) -{ - if (unlikely(!io)) - return false; - - if (io->debug_destroy) - io->debug_destroy(io->debug_data); - - io->debug_handler = callback; - io->debug_destroy = destroy; - io->debug_data = user_data; - - return true; -} diff --git a/ell/io.h b/ell/io.h deleted file mode 100644 index 0689d08..0000000 --- a/ell/io.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_IO_H -#define __ELL_IO_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_io; - -typedef void (*l_io_debug_cb_t) (const char *str, void *user_data); - -typedef bool (*l_io_read_cb_t) (struct l_io *io, void *user_data); -typedef bool (*l_io_write_cb_t) (struct l_io *io, void *user_data); -typedef void (*l_io_disconnect_cb_t) (struct l_io *io, void *user_data); -typedef void (*l_io_destroy_cb_t) (void *user_data); - -struct l_io *l_io_new(int fd); -void l_io_destroy(struct l_io *io); - -int l_io_get_fd(struct l_io *io); -bool l_io_set_close_on_destroy(struct l_io *io, bool do_close); - -bool l_io_set_read_handler(struct l_io *io, l_io_read_cb_t callback, - void *user_data, l_io_destroy_cb_t destroy); -bool l_io_set_write_handler(struct l_io *io, l_io_write_cb_t callback, - void *user_data, l_io_destroy_cb_t destroy); -bool l_io_set_disconnect_handler(struct l_io *io, - l_io_disconnect_cb_t callback, - void *user_data, l_io_destroy_cb_t destroy); - -bool l_io_set_debug(struct l_io *io, l_io_debug_cb_t callback, - void *user_data, l_io_destroy_cb_t destroy); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_IO_H */ diff --git a/ell/key.c b/ell/key.c deleted file mode 100644 index 3472288..0000000 --- a/ell/key.c +++ /dev/null @@ -1,818 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2016 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include - -#include "private.h" -#include "util.h" -#include "key.h" -#include "string.h" -#include "random.h" -#include "missing.h" - -#ifndef KEYCTL_DH_COMPUTE -#define KEYCTL_DH_COMPUTE 23 -#endif - -#ifndef KEYCTL_PKEY_QUERY -#define KEYCTL_PKEY_QUERY 24 -#define KEYCTL_PKEY_ENCRYPT 25 -#define KEYCTL_PKEY_DECRYPT 26 -#define KEYCTL_PKEY_SIGN 27 -#define KEYCTL_PKEY_VERIFY 28 - -#define KEYCTL_SUPPORTS_ENCRYPT 0x01 -#define KEYCTL_SUPPORTS_DECRYPT 0x02 -#define KEYCTL_SUPPORTS_SIGN 0x04 -#define KEYCTL_SUPPORTS_VERIFY 0x08 - -struct keyctl_pkey_query { - uint32_t supported_ops; - uint32_t key_size; - uint16_t max_data_size; - uint16_t max_sig_size; - uint16_t max_enc_size; - uint16_t max_dec_size; - - uint32_t __spare[10]; -}; - -struct keyctl_pkey_params { - int32_t key_id; - uint32_t in_len; - union { - uint32_t out_len; - uint32_t in2_len; - }; - uint32_t __spare[7]; -}; - -/* Work around the missing (pre-4.7) or broken (4.14.{70,71,72} and - * 4.18.{8,9,10}) kernel declaration of struct keyctl_dh_params - */ -struct dh_params { - int32_t private; - int32_t prime; - int32_t base; -}; -#else -/* When KEYCTL_PKEY_QUERY is defined by the kernel, the - * struct keyctl_dh_params declaration is valid. - */ -#define dh_params keyctl_dh_params -#endif - -#ifndef KEYCTL_RESTRICT_KEYRING -#define KEYCTL_RESTRICT_KEYRING 29 -#endif - -static int32_t internal_keyring; - -struct l_key { - int type; - int32_t serial; -}; - -struct l_keyring { - int32_t serial; -}; - -static const char * const key_type_names[] = { - [L_KEY_RAW] = "user", - [L_KEY_RSA] = "asymmetric", -}; - -static long kernel_add_key(const char *type, const char *description, - const void *payload, size_t len, int32_t keyring) -{ - long result; - - result = syscall(__NR_add_key, type, description, payload, len, - keyring); - - return result >= 0 ? result : -errno; -} - -static long kernel_read_key(int32_t serial, const void *payload, size_t len) -{ - long result; - - result = syscall(__NR_keyctl, KEYCTL_READ, serial, payload, len); - - return result >= 0 ? result : -errno; -} - -static long kernel_update_key(int32_t serial, const void *payload, size_t len) -{ - long result; - - result = syscall(__NR_keyctl, KEYCTL_UPDATE, serial, payload, len); - - return result >= 0 ? result : -errno; -} - -static long kernel_invalidate_key(int32_t serial) -{ - long result; - - result = syscall(__NR_keyctl, KEYCTL_INVALIDATE, serial); - - return result >= 0 ? result : -errno; -} - -static long kernel_link_key(int32_t key_serial, int32_t ring_serial) -{ - long result; - - result = syscall(__NR_keyctl, KEYCTL_LINK, key_serial, ring_serial); - - return result >= 0 ? result : -errno; -} - -static long kernel_unlink_key(int32_t key_serial, int32_t ring_serial) -{ - long result; - - result = syscall(__NR_keyctl, KEYCTL_UNLINK, key_serial, ring_serial); - - return result >= 0 ? result : -errno; -} - -static char *format_key_info(const char *encoding, const char *hash) -{ - struct l_string *info; - - if (!encoding && !hash) - return NULL; - - info = l_string_new(0); - - if (encoding) - l_string_append_printf(info, "enc=%s ", encoding); - - if (hash) - l_string_append_printf(info, "hash=%s", hash); - - return l_string_unwrap(info); -} - -static long kernel_query_key(int32_t key_serial, const char *encoding, - const char *hash, size_t *size, bool *public) -{ - long result; - struct keyctl_pkey_query query; - char *info = format_key_info(encoding, hash); - - memset(&query, 0, sizeof(query)); - - result = syscall(__NR_keyctl, KEYCTL_PKEY_QUERY, key_serial, 0, - info ?: "", &query); - if (result == 0) { - *size = query.key_size; - *public = ((query.supported_ops & KEYCTL_SUPPORTS_ENCRYPT) && - !(query.supported_ops & KEYCTL_SUPPORTS_DECRYPT)); - } - l_free(info); - - return result >= 0 ? result : -errno; -} - -static long kernel_dh_compute(int32_t private, int32_t prime, int32_t base, - void *payload, size_t len) -{ - long result; - - struct dh_params params = { .private = private, - .prime = prime, - .base = base }; - - result = syscall(__NR_keyctl, KEYCTL_DH_COMPUTE, ¶ms, payload, len, - NULL); - - return result >= 0 ? result : -errno; -} - -static long kernel_restrict_keyring(int32_t serial, const char *keytype, - const char *restriction) -{ - long result; - - result = syscall(__NR_keyctl, KEYCTL_RESTRICT_KEYRING, serial, keytype, - restriction); - - return result >= 0 ? result : -errno; -} - -static long kernel_key_eds(int op, int32_t serial, const char *encoding, - const char *hash, const void *in, void *out, - size_t len_in, size_t len_out) -{ - long result; - struct keyctl_pkey_params params = { .key_id = serial, - .in_len = len_in, - .out_len = len_out }; - char *info = format_key_info(encoding, hash); - - memset(out, 0, len_out); - - result = syscall(__NR_keyctl, op, ¶ms, info ?: "", in, out); - l_free(info); - - return result >= 0 ? result : -errno; -} - -static long kernel_key_verify(int32_t serial, - const char *encoding, const char *hash, - const void *data, size_t data_len, - const void *sig, size_t sig_len) -{ - struct keyctl_pkey_params params = { - .key_id = serial, - .in_len = data_len, - .in2_len = sig_len, - }; - char *info = format_key_info(encoding, hash); - long result; - - result = syscall(__NR_keyctl, KEYCTL_PKEY_VERIFY, ¶ms, - info ?: "", data, sig); - l_free(info); - - return result >= 0 ? result : -errno; -} - -static bool setup_internal_keyring(void) -{ - internal_keyring = kernel_add_key("keyring", "ell-internal", NULL, 0, - KEY_SPEC_THREAD_KEYRING); - - if (internal_keyring <= 0) { - internal_keyring = 0; - return false; - } - - return true; -} - -LIB_EXPORT struct l_key *l_key_new(enum l_key_type type, const void *payload, - size_t payload_length) -{ - struct l_key *key; - char *description; - static unsigned long key_idx; - - if (unlikely(!payload)) - return NULL; - - if (unlikely((size_t)type >= L_ARRAY_SIZE(key_type_names))) - return NULL; - - if (!internal_keyring && !setup_internal_keyring()) - return NULL; - - key = l_new(struct l_key, 1); - key->type = type; - description = l_strdup_printf("ell-key-%lu", key_idx++); - key->serial = kernel_add_key(key_type_names[type], description, payload, - payload_length, internal_keyring); - l_free(description); - - if (key->serial < 0) { - l_free(key); - key = NULL; - } - - /* - * TODO: Query asymmetric key algorithm from the kernel and - * ensure that it matches the expected l_key_type. This can - * currently be found by digging through /proc/keys, but a - * keyctl() op makes more sense. - */ - - return key; -} - -LIB_EXPORT void l_key_free(struct l_key *key) -{ - if (unlikely(!key)) - return; - - /* - * Use invalidate as, unlike revoke, this doesn't delay the - * key garbage collection and causes the quota used by the - * key to be released sooner and more predictably. - */ - kernel_invalidate_key(key->serial); - - l_free(key); -} - -LIB_EXPORT void l_key_free_norevoke(struct l_key *key) -{ - if (unlikely(!key)) - return; - - kernel_unlink_key(key->serial, internal_keyring); - - l_free(key); -} - -LIB_EXPORT bool l_key_update(struct l_key *key, const void *payload, size_t len) -{ - long error; - - if (unlikely(!key)) - return false; - - error = kernel_update_key(key->serial, payload, len); - - return error == 0; -} - -LIB_EXPORT bool l_key_extract(struct l_key *key, void *payload, size_t *len) -{ - long keylen; - - if (unlikely(!key)) - return false; - - keylen = kernel_read_key(key->serial, payload, *len); - - if (keylen < 0 || (size_t)keylen > *len) { - explicit_bzero(payload, *len); - return false; - } - - *len = keylen; - return true; -} - -LIB_EXPORT ssize_t l_key_get_payload_size(struct l_key *key) -{ - return kernel_read_key(key->serial, NULL, 0); -} - -static const char *lookup_cipher(enum l_key_cipher_type cipher) -{ - const char* ret = NULL; - - switch (cipher) { - case L_KEY_RSA_PKCS1_V1_5: - ret = "pkcs1"; - break; - case L_KEY_RSA_RAW: - ret = "raw"; - break; - } - - return ret; -} - -static const char *lookup_checksum(enum l_checksum_type checksum) -{ - const char* ret = NULL; - - switch (checksum) { - case L_CHECKSUM_NONE: - break; - case L_CHECKSUM_MD4: - ret = "md4"; - break; - case L_CHECKSUM_MD5: - ret = "md5"; - break; - case L_CHECKSUM_SHA1: - ret = "sha1"; - break; - case L_CHECKSUM_SHA224: - ret = "sha224"; - break; - case L_CHECKSUM_SHA256: - ret = "sha256"; - break; - case L_CHECKSUM_SHA384: - ret = "sha384"; - break; - case L_CHECKSUM_SHA512: - ret = "sha512"; - break; - } - - return ret; -} - -LIB_EXPORT bool l_key_get_info(struct l_key *key, enum l_key_cipher_type cipher, - enum l_checksum_type checksum, size_t *bits, - bool *public) -{ - if (unlikely(!key)) - return false; - - return !kernel_query_key(key->serial, lookup_cipher(cipher), - lookup_checksum(checksum), bits, - public); -} - -LIB_EXPORT struct l_key *l_key_generate_dh_private(const void *prime_buf, - size_t prime_len) -{ - uint8_t *buf; - const uint8_t *prime = prime_buf; - size_t prime_bits; - unsigned int i; - size_t private_bytes; - size_t random_bytes; - struct l_key *private; - - /* Find the prime's bit length excluding leading 0s */ - - for (i = 0; i < prime_len && !prime[i]; i++); - - if (i == prime_len || (i == prime_len - 1 && prime[i] < 5)) - return NULL; - - prime_bits = (prime_len - i) * 8 - __builtin_clz(prime[i]); - - /* - * Generate a random DH private value conforming to 1 < x < p - 1. - * To do this covering all possible values in this range with the - * same probability of generating each value generally requires - * looping. Instead we generate a value in the range - * [2 ^ (prime_bits - 2), 2 ^ (prime_bits - 1) - 1] by forcing bit - * prime_bits - 2 to 1, i.e. the range in PKCS #3 Section 7.1 for - * l equal to prime_bits - 1. This means we're using between - * one half and one quarter of the full [2, p - 2] range, i.e. - * between 1 and 2 bits fewer. Note that since p is odd - * p - 1 has the same bit length as p and so our maximum value - * 2 ^ (prime_bits - 1) - 1 is still less than p - 1. - */ - private_bytes = ((prime_bits - 1) + 7) / 8; - random_bytes = ((prime_bits - 2) + 7) / 8; - buf = l_malloc(private_bytes); - l_getrandom(buf + private_bytes - random_bytes, random_bytes); - - buf[0] &= (1 << ((prime_bits - 2) % 8)) - 1; - buf[0] |= 1 << ((prime_bits - 2) % 8); - - private = l_key_new(L_KEY_RAW, buf, private_bytes); - explicit_bzero(buf, private_bytes); - l_free(buf); - return private; -} - -static bool compute_common(struct l_key *base, struct l_key *private, - struct l_key *prime, void *payload, size_t *len) -{ - long result_len; - bool usable_payload = *len != 0; - - result_len = kernel_dh_compute(private->serial, prime->serial, - base->serial, payload, *len); - - if (result_len > 0) { - *len = result_len; - return usable_payload; - } else { - return false; - } -} - -LIB_EXPORT bool l_key_compute_dh_public(struct l_key *generator, - struct l_key *private, - struct l_key *prime, - void *payload, size_t *len) -{ - return compute_common(generator, private, prime, payload, len); -} - -LIB_EXPORT bool l_key_compute_dh_secret(struct l_key *other_public, - struct l_key *private, - struct l_key *prime, - void *payload, size_t *len) -{ - return compute_common(other_public, private, prime, payload, len); -} - -static int be_bignum_compare(const uint8_t *a, size_t a_len, - const uint8_t *b, size_t b_len) -{ - unsigned int i; - - if (a_len >= b_len) { - for (i = 0; i < a_len - b_len; i++) - if (a[i]) - return 1; - - return memcmp(a + i, b, b_len); - } else { - for (i = 0; i < b_len - a_len; i++) - if (b[i]) - return -1; - - return memcmp(a, b + i, a_len); - } -} - -/* - * Validate that @payload is within range for a private and public key for - * a DH computation in the finite field group defined by modulus @prime_buf, - * both numbers stored as big-endian integers. We require a key in the - * [2, prime - 2] (inclusive) interval. PKCS #3 does not exclude 1 as a - * private key but other specs do. - */ -LIB_EXPORT bool l_key_validate_dh_payload(const void *payload, size_t len, - const void *prime_buf, size_t prime_len) -{ - static const uint8_t one[] = { 1 }; - uint8_t prime_1[prime_len]; - - /* - * Produce prime - 1 for the payload < prime - 1 check. - * prime is odd so just zero the LSB. - */ - memcpy(prime_1, prime_buf, prime_len); - - if (prime_len < 1 || !(prime_1[prime_len - 1] & 1)) - return false; - - prime_1[prime_len - 1] &= ~1; - - if (be_bignum_compare(payload, len, one, 1) <= 0) - return false; - - if (be_bignum_compare(payload, len, prime_1, prime_len) >= 0) - return false; - - return true; -} - -/* Common code for encrypt/decrypt/sign */ -static ssize_t eds_common(struct l_key *key, - enum l_key_cipher_type cipher, - enum l_checksum_type checksum, const void *in, - void *out, size_t len_in, size_t len_out, - int op) -{ - if (unlikely(!key)) - return -EINVAL; - - return kernel_key_eds(op, key->serial, lookup_cipher(cipher), - lookup_checksum(checksum), in, out, len_in, - len_out); -} - -LIB_EXPORT ssize_t l_key_encrypt(struct l_key *key, - enum l_key_cipher_type cipher, - enum l_checksum_type checksum, - const void *in, void *out, - size_t len_in, size_t len_out) -{ - ssize_t ret_len; - - ret_len = eds_common(key, cipher, checksum, in, out, - len_in, len_out, - KEYCTL_PKEY_ENCRYPT); - - return ret_len; -} - -LIB_EXPORT ssize_t l_key_decrypt(struct l_key *key, - enum l_key_cipher_type cipher, - enum l_checksum_type checksum, - const void *in, void *out, - size_t len_in, size_t len_out) -{ - ssize_t ret_len; - - ret_len = eds_common(key, cipher, checksum, in, out, len_in, - len_out, KEYCTL_PKEY_DECRYPT); - - if (ret_len < 0) - goto done; - -done: - return ret_len; -} - -LIB_EXPORT ssize_t l_key_sign(struct l_key *key, - enum l_key_cipher_type cipher, - enum l_checksum_type checksum, const void *in, - void *out, size_t len_in, size_t len_out) -{ - ssize_t ret_len; - - ret_len = eds_common(key, cipher, checksum, in, out, - len_in, len_out, - KEYCTL_PKEY_SIGN); - - return ret_len; -} - -LIB_EXPORT bool l_key_verify(struct l_key *key, - enum l_key_cipher_type cipher, - enum l_checksum_type checksum, const void *data, - const void *sig, size_t len_data, - size_t len_sig) -{ - long result; - - if (unlikely(!key)) - return false; - - result = kernel_key_verify(key->serial, lookup_cipher(cipher), - lookup_checksum(checksum), - data, len_data, - sig, len_sig); - - return result >= 0; -} - -LIB_EXPORT struct l_keyring *l_keyring_new(void) -{ - struct l_keyring *keyring; - char *description; - static unsigned long keyring_idx; - - if (!internal_keyring && !setup_internal_keyring()) - return NULL; - - keyring = l_new(struct l_keyring, 1); - description = l_strdup_printf("ell-keyring-%lu", keyring_idx++); - keyring->serial = kernel_add_key("keyring", description, NULL, 0, - internal_keyring); - l_free(description); - - if (keyring->serial < 0) { - l_free(keyring); - return NULL; - } - - return keyring; -} - -LIB_EXPORT bool l_keyring_restrict(struct l_keyring *keyring, - enum l_keyring_restriction res, - const struct l_keyring *trusted) -{ - char *restriction = NULL; - long result; - - switch (res) { - case L_KEYRING_RESTRICT_ASYM: - case L_KEYRING_RESTRICT_ASYM_CHAIN: - { - char *option = ""; - - if (res == L_KEYRING_RESTRICT_ASYM_CHAIN) - option = ":chain"; - - restriction = l_strdup_printf("key_or_keyring:%d%s", - trusted ? trusted->serial : 0, - option); - - break; - } - default: - /* Unsupported type */ - return NULL; - } - - result = kernel_restrict_keyring(keyring->serial, "asymmetric", - restriction); - - l_free(restriction); - - return result == 0; -} - -LIB_EXPORT void l_keyring_free(struct l_keyring *keyring) -{ - if (unlikely(!keyring)) - return; - - kernel_invalidate_key(keyring->serial); - - l_free(keyring); -} - -LIB_EXPORT void l_keyring_free_norevoke(struct l_keyring *keyring) -{ - if (unlikely(!keyring)) - return; - - kernel_unlink_key(keyring->serial, internal_keyring); - - l_free(keyring); -} - -LIB_EXPORT bool l_keyring_link(struct l_keyring *keyring, - const struct l_key *key) -{ - long error; - - if (unlikely(!keyring) || unlikely(!key)) - return false; - - error = kernel_link_key(key->serial, keyring->serial); - - return error == 0; -} - -LIB_EXPORT bool l_keyring_unlink(struct l_keyring *keyring, - const struct l_key *key) -{ - long error; - - if (unlikely(!keyring) || unlikely(!key)) - return false; - - error = kernel_unlink_key(key->serial, keyring->serial); - - return error == 0; -} - -LIB_EXPORT bool l_keyring_link_nested(struct l_keyring *keyring, - const struct l_keyring *nested) -{ - long error; - - if (unlikely(!keyring) || unlikely(!nested)) - return false; - - error = kernel_link_key(nested->serial, keyring->serial); - - return error == 0; -} - -LIB_EXPORT bool l_keyring_unlink_nested(struct l_keyring *keyring, - const struct l_keyring *nested) -{ - long error; - - if (unlikely(!keyring) || unlikely(!nested)) - return false; - - error = kernel_unlink_key(nested->serial, keyring->serial); - - return error == 0; -} - -LIB_EXPORT bool l_key_is_supported(uint32_t features) -{ - long result; - - if (features & L_KEY_FEATURE_DH) { - result = syscall(__NR_keyctl, KEYCTL_DH_COMPUTE, NULL, "x", 1, - NULL); - - if (result == -1 && errno == EOPNOTSUPP) - return false; - } - - if (features & L_KEY_FEATURE_RESTRICT) { - result = syscall(__NR_keyctl, KEYCTL_RESTRICT_KEYRING, 0, - "asymmetric", ""); - - if (result == -1 && errno == EOPNOTSUPP) - return false; - } - - if (features & L_KEY_FEATURE_CRYPTO) { - result = syscall(__NR_keyctl, KEYCTL_PKEY_QUERY, 0, 0, "", 0); - - if (result == -1 && errno == EOPNOTSUPP) - return false; - } - - return true; -} diff --git a/ell/key.h b/ell/key.h deleted file mode 100644 index f1f95e1..0000000 --- a/ell/key.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2016 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_KEY_H -#define __ELL_KEY_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#include - -struct l_key; -struct l_keyring; - -enum l_key_feature { - L_KEY_FEATURE_DH = 1 << 0, - L_KEY_FEATURE_RESTRICT = 1 << 1, - L_KEY_FEATURE_CRYPTO = 1 << 2, -}; - -enum l_key_type { - L_KEY_RAW = 0, - L_KEY_RSA, -}; - -enum l_keyring_restriction { - L_KEYRING_RESTRICT_ASYM = 0, - L_KEYRING_RESTRICT_ASYM_CHAIN, -}; - -enum l_key_cipher_type { - L_KEY_RSA_PKCS1_V1_5, - L_KEY_RSA_RAW, -}; - -struct l_key *l_key_new(enum l_key_type type, const void *payload, - size_t payload_length); - -void l_key_free(struct l_key *key); -void l_key_free_norevoke(struct l_key *key); - -bool l_key_update(struct l_key *key, const void *payload, size_t len); - -bool l_key_extract(struct l_key *key, void *payload, size_t *len); - -ssize_t l_key_get_payload_size(struct l_key *key); - -bool l_key_get_info(struct l_key *key, enum l_key_cipher_type cipher, - enum l_checksum_type checksum, size_t *bits, - bool *out_public); - -struct l_key *l_key_generate_dh_private(const void *prime_buf, - size_t prime_len); - -bool l_key_compute_dh_public(struct l_key *generator, struct l_key *private_key, - struct l_key *prime, - void *payload, size_t *len); - -bool l_key_compute_dh_secret(struct l_key *other_public, struct l_key *private_key, - struct l_key *prime, - void *payload, size_t *len); - -bool l_key_validate_dh_payload(const void *payload, size_t len, - const void *prime_buf, size_t prime_len); - -ssize_t l_key_encrypt(struct l_key *key, enum l_key_cipher_type cipher, - enum l_checksum_type checksum, const void *in, - void *out, size_t len_in, size_t len_out); - -ssize_t l_key_decrypt(struct l_key *key, enum l_key_cipher_type cipher, - enum l_checksum_type checksum, const void *in, - void *out, size_t len_in, size_t len_out); - -ssize_t l_key_sign(struct l_key *key, enum l_key_cipher_type cipher, - enum l_checksum_type checksum, const void *in, - void *out, size_t len_in, size_t len_out); - -bool l_key_verify(struct l_key *key, enum l_key_cipher_type cipher, - enum l_checksum_type checksum, const void *data, - const void *sig, size_t len_data, size_t len_sig); - -struct l_keyring *l_keyring_new(void); - -bool l_keyring_restrict(struct l_keyring *keyring, enum l_keyring_restriction res, - const struct l_keyring *trust); - -void l_keyring_free(struct l_keyring *keyring); -void l_keyring_free_norevoke(struct l_keyring *keyring); - -bool l_keyring_link(struct l_keyring *keyring, const struct l_key *key); - -bool l_keyring_unlink(struct l_keyring *keyring, const struct l_key *key); - -bool l_keyring_link_nested(struct l_keyring *keyring, - const struct l_keyring *nested); -bool l_keyring_unlink_nested(struct l_keyring *keyring, - const struct l_keyring *nested); - -bool l_key_is_supported(uint32_t features); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_KEY_H */ diff --git a/ell/log.c b/ell/log.c deleted file mode 100644 index 5560b0c..0000000 --- a/ell/log.c +++ /dev/null @@ -1,457 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#include "queue.h" -#include "log.h" -#include "private.h" - -struct debug_section { - struct l_debug_desc *start; - struct l_debug_desc *end; -}; - -struct l_queue *debug_sections; - -/** - * SECTION:log - * @short_description: Logging framework - * - * Logging framework - */ - -/** - * l_debug_desc: - * - * Debug descriptor. - */ - -static void log_null(int priority, const char *file, const char *line, - const char *func, const char *format, va_list ap) -{ -} - -static l_log_func_t log_func = log_null; -static const char *log_ident = ""; -static int log_fd = -1; -static unsigned long log_pid; - -static inline void close_log(void) -{ - if (log_fd > 0) { - close(log_fd); - log_fd = -1; - } -} - -static int open_log(const char *path) -{ - struct sockaddr_un addr; - - log_fd = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (log_fd < 0) - return -1; - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); - - if (connect(log_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - close_log(); - return -1; - } - - return 0; -} - -/** - * l_log_set_ident: - * @ident: string identifier - * - * Sets the log identifier string. - **/ -LIB_EXPORT void l_log_set_ident(const char *ident) -{ - log_ident = ident; -} - -/** - * l_log_set_handler: - * @function: log handler function - * - * Sets the log handler function. - **/ -LIB_EXPORT void l_log_set_handler(l_log_func_t function) -{ - L_DEBUG_SYMBOL(__debug_intern, ""); - - close_log(); - - if (!function) { - log_func = log_null; - return; - } - - log_func = function; -} - -/** - * l_log_set_null: - * - * Disable logging. - **/ -LIB_EXPORT void l_log_set_null(void) -{ - close_log(); - - log_func = log_null; -} - -static void log_stderr(int priority, const char *file, const char *line, - const char *func, const char *format, va_list ap) -{ - vfprintf(stderr, format, ap); -} - -/** - * l_log_set_stderr: - * - * Enable logging to stderr. - **/ -LIB_EXPORT void l_log_set_stderr(void) -{ - close_log(); - - log_func = log_stderr; -} - -static void log_syslog(int priority, const char *file, const char *line, - const char *func, const char *format, va_list ap) -{ - struct msghdr msg; - struct iovec iov[2]; - char hdr[64], *str; - int hdr_len, str_len; - - str_len = vasprintf(&str, format, ap); - if (str_len < 0) - return; - - hdr_len = snprintf(hdr, sizeof(hdr), "<%i>%s[%lu]: ", priority, - log_ident, (unsigned long) log_pid); - - iov[0].iov_base = hdr; - iov[0].iov_len = hdr_len; - iov[1].iov_base = str; - iov[1].iov_len = str_len; - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = iov; - msg.msg_iovlen = 2; - - sendmsg(log_fd, &msg, 0); - - free(str); -} - -/** - * l_log_set_syslog: - * - * Enable logging to syslog. - **/ -LIB_EXPORT void l_log_set_syslog(void) -{ - close_log(); - - if (open_log("/dev/log") < 0) { - log_func = log_null; - return; - } - - log_pid = getpid(); - - log_func = log_syslog; -} - -static void log_journal(int priority, const char *file, const char *line, - const char *func, const char *format, va_list ap) -{ - struct msghdr msg; - struct iovec iov[12]; - char prio[16], *str; - int prio_len, str_len; - - str_len = vasprintf(&str, format, ap); - if (str_len < 0) - return; - - prio_len = snprintf(prio, sizeof(prio), "PRIORITY=%u\n", priority); - - iov[0].iov_base = "MESSAGE="; - iov[0].iov_len = 8; - iov[1].iov_base = str; - iov[1].iov_len = str_len; - iov[2].iov_base = prio; - iov[2].iov_len = prio_len; - iov[3].iov_base = "CODE_FILE="; - iov[3].iov_len = 10; - iov[4].iov_base = (char *) file; - iov[4].iov_len = strlen(file); - iov[5].iov_base = "\n"; - iov[5].iov_len = 1; - iov[6].iov_base = "CODE_LINE="; - iov[6].iov_len = 10; - iov[7].iov_base = (char *) line; - iov[7].iov_len = strlen(line); - iov[8].iov_base = "\n"; - iov[8].iov_len = 1; - iov[9].iov_base = "CODE_FUNC="; - iov[9].iov_len = 10; - iov[10].iov_base = (char *) func; - iov[10].iov_len = strlen(func); - iov[11].iov_base = "\n"; - iov[11].iov_len = 1; - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = iov; - msg.msg_iovlen = 12; - - sendmsg(log_fd, &msg, 0); - - free(str); -} - -/** - * l_log_set_journal: - * - * Enable logging to journal. - **/ -LIB_EXPORT void l_log_set_journal(void) -{ - close_log(); - - if (open_log("/run/systemd/journal/socket") < 0) { - log_func = log_null; - return; - } - - log_pid = getpid(); - - log_func = log_journal; -} - -/** - * l_log_with_location: - * @priority: priority level - * @file: source file - * @line: source line - * @func: source function - * @format: format string - * @...: format arguments - * - * Log information. - **/ -LIB_EXPORT void l_log_with_location(int priority, - const char *file, const char *line, - const char *func, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - log_func(priority, file, line, func, format, ap); - va_end(ap); -} - -/** - * l_error: - * @format: format string - * @...: format arguments - * - **/ - -/** - * l_warn: - * @format: format string - * @...: format arguments - * - **/ - -/** - * l_info: - * @format: format string - * @...: format arguments - * - **/ - -/** - * l_debug: - * @format: format string - * @...: format arguments - **/ - -static const char *debug_pattern; - -void debug_enable(struct l_debug_desc *start, struct l_debug_desc *stop) -{ - struct l_debug_desc *desc; - char *pattern_copy; - - if (!debug_pattern) - return; - - pattern_copy = strdupa(debug_pattern); - - while (pattern_copy) { - char *str = strsep(&pattern_copy, ":,"); - if (!str) - break; - - for (desc = start; desc < stop; desc++) { - if (!fnmatch(str, desc->file, 0)) - desc->flags |= L_DEBUG_FLAG_PRINT; - if (!fnmatch(str, desc->func, 0)) - desc->flags |= L_DEBUG_FLAG_PRINT; - } - } -} - -void debug_disable(struct l_debug_desc *start, struct l_debug_desc *stop) -{ - struct l_debug_desc *desc; - - for (desc = start; desc < stop; desc++) - desc->flags &= ~L_DEBUG_FLAG_PRINT; -} - -/** - * l_debug_add_section: - * @start: start of the debug section - * @stop: stop of the debug section - * - * Add information about a debug section. This is used by shared libraries - * to tell ell about their debug section start & stopping points. This is used - * to make l_debug statements work across all shared libraries that might be - * linked into the executable - */ -LIB_EXPORT void l_debug_add_section(struct l_debug_desc *start, - struct l_debug_desc *end) -{ - const struct l_queue_entry *entry; - const struct debug_section *section; - struct debug_section *new_section; - - if (!debug_sections) { - debug_sections = l_queue_new(); - goto add; - } - - for (entry = l_queue_get_entries(debug_sections); entry; - entry = entry->next) { - section = entry->data; - - if (section->start == start && section->end == end) - return; - } - -add: - new_section = l_new(struct debug_section, 1); - new_section->start = start; - new_section->end = end; - - l_queue_push_head(debug_sections, new_section); -} - -/** - * l_debug_enable_full: - * @pattern: debug pattern - * @start: start of the debug section - * @stop: end of the debug section - * - * Enable debug sections based on @pattern. - **/ -LIB_EXPORT void l_debug_enable_full(const char *pattern, - struct l_debug_desc *start, - struct l_debug_desc *end) -{ - const struct l_queue_entry *entry; - const struct debug_section *section; - - if (!pattern) - return; - - debug_pattern = pattern; - - l_debug_add_section(start, end); - - for (entry = l_queue_get_entries(debug_sections); entry; - entry = entry->next) { - section = entry->data; - debug_enable(section->start, section->end); - } -} - -/** - * l_debug_disable: - * - * Disable all debug sections. - **/ -LIB_EXPORT void l_debug_disable(void) -{ - const struct l_queue_entry *entry; - const struct debug_section *section; - - for (entry = l_queue_get_entries(debug_sections); entry; - entry = entry->next) { - section = entry->data; - debug_disable(section->start, section->end); - } - - debug_pattern = NULL; -} - -__attribute__((constructor)) static void register_debug_section() -{ - extern struct l_debug_desc __start___ell_debug[]; - extern struct l_debug_desc __stop___ell_debug[]; - - l_debug_add_section(__start___ell_debug, __stop___ell_debug); -} - -__attribute__((destructor(65535))) static void free_debug_sections() -{ - l_queue_destroy(debug_sections, l_free); -} diff --git a/ell/log.h b/ell/log.h deleted file mode 100644 index 19bf10b..0000000 --- a/ell/log.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_LOG_H -#define __ELL_LOG_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define L_LOG_ERR 3 -#define L_LOG_WARNING 4 -#define L_LOG_INFO 6 -#define L_LOG_DEBUG 7 - -typedef void (*l_log_func_t) (int priority, const char *file, const char *line, - const char *func, const char *format, va_list ap); - -void l_log_set_ident(const char *ident); -void l_log_set_handler(l_log_func_t function); -void l_log_set_null(void); -void l_log_set_stderr(void); -void l_log_set_syslog(void); -void l_log_set_journal(void); - -void l_log_with_location(int priority, const char *file, const char *line, - const char *func, const char *format, ...) - __attribute__((format(printf, 5, 6))); - -#define l_log(priority, format, ...) l_log_with_location(priority, \ - __FILE__, L_STRINGIFY(__LINE__), \ - __func__, format "\n", ##__VA_ARGS__) - -struct l_debug_desc { - const char *file; - const char *func; -#define L_DEBUG_FLAG_DEFAULT (0) -#define L_DEBUG_FLAG_PRINT (1 << 0) - unsigned int flags; -} __attribute__((aligned(8))); - -#define L_DEBUG_SYMBOL(symbol, format, ...) do { \ - static struct l_debug_desc symbol \ - __attribute__((used, section("__ell_debug"), aligned(8))) = { \ - .file = __FILE__, .func = __func__, \ - .flags = L_DEBUG_FLAG_DEFAULT, \ - }; \ - if (symbol.flags & L_DEBUG_FLAG_PRINT) \ - l_log(L_LOG_DEBUG, "%s:%s() " format, __FILE__, \ - __func__ , ##__VA_ARGS__); \ -} while (0) - -void l_debug_enable_full(const char *pattern, - struct l_debug_desc *start, - struct l_debug_desc *stop); -void l_debug_add_section(struct l_debug_desc *start, - struct l_debug_desc *end); - -#define l_debug_enable(pattern) do { \ -_Pragma("GCC diagnostic push") \ -_Pragma("GCC diagnostic ignored \"-Wredundant-decls\"") \ - extern struct l_debug_desc __start___ell_debug[]; \ - extern struct l_debug_desc __stop___ell_debug[]; \ - l_debug_enable_full(pattern, __start___ell_debug, __stop___ell_debug); \ -_Pragma("GCC diagnostic pop") \ -} while (0) - -void l_debug_disable(void); - -#define l_error(format, ...) l_log(L_LOG_ERR, format, ##__VA_ARGS__) -#define l_warn(format, ...) l_log(L_LOG_WARNING, format, ##__VA_ARGS__) -#define l_info(format, ...) l_log(L_LOG_INFO, format, ##__VA_ARGS__) -#define l_debug(format, ...) L_DEBUG_SYMBOL(__debug_desc, format, ##__VA_ARGS__) - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_LOG_H */ diff --git a/ell/main.c b/ell/main.c deleted file mode 100644 index a2f0bf6..0000000 --- a/ell/main.c +++ /dev/null @@ -1,665 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "signal.h" -#include "queue.h" -#include "log.h" -#include "util.h" -#include "main.h" -#include "private.h" -#include "timeout.h" - -/** - * SECTION:main - * @short_description: Main loop handling - * - * Main loop handling - */ - -#define MAX_EPOLL_EVENTS 10 - -#define IDLE_FLAG_DISPATCHING 1 -#define IDLE_FLAG_DESTROYED 2 - -#define WATCH_FLAG_DISPATCHING 1 -#define WATCH_FLAG_DESTROYED 2 - -#define WATCHDOG_TRIGGER_FREQ 2 - -static int epoll_fd; -static bool epoll_running; -static bool epoll_terminate; -static int idle_id; - -static int notify_fd; - -static struct l_timeout *watchdog; - -static struct l_queue *idle_list; - -struct watch_data { - int fd; - uint32_t events; - uint32_t flags; - watch_event_cb_t callback; - watch_destroy_cb_t destroy; - void *user_data; -}; - -#define DEFAULT_WATCH_ENTRIES 128 - -static unsigned int watch_entries; -static struct watch_data **watch_list; - -struct idle_data { - idle_event_cb_t callback; - idle_destroy_cb_t destroy; - void *user_data; - uint32_t flags; - int id; -}; - -static inline bool __attribute__ ((always_inline)) create_epoll(void) -{ - unsigned int i; - - epoll_fd = epoll_create1(EPOLL_CLOEXEC); - if (epoll_fd < 0) { - epoll_fd = 0; - return false; - } - - watch_list = malloc(DEFAULT_WATCH_ENTRIES * sizeof(void *)); - if (!watch_list) - goto close_epoll; - - idle_list = l_queue_new(); - - idle_id = 0; - - watch_entries = DEFAULT_WATCH_ENTRIES; - - for (i = 0; i < watch_entries; i++) - watch_list[i] = NULL; - - return true; - -close_epoll: - close(epoll_fd); - epoll_fd = 0; - - return false; -} - -int watch_add(int fd, uint32_t events, watch_event_cb_t callback, - void *user_data, watch_destroy_cb_t destroy) -{ - struct watch_data *data; - struct epoll_event ev; - int err; - - if (unlikely(fd < 0 || !callback)) - return -EINVAL; - - if (!epoll_fd) - return -EIO; - - if ((unsigned int) fd > watch_entries - 1) - return -ERANGE; - - data = l_new(struct watch_data, 1); - - data->fd = fd; - data->events = events; - data->flags = 0; - data->callback = callback; - data->destroy = destroy; - data->user_data = user_data; - - memset(&ev, 0, sizeof(ev)); - ev.events = events; - ev.data.ptr = data; - - err = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, data->fd, &ev); - if (err < 0) { - l_free(data); - return -errno; - } - - watch_list[fd] = data; - - return 0; -} - -int watch_modify(int fd, uint32_t events, bool force) -{ - struct watch_data *data; - struct epoll_event ev; - int err; - - if (unlikely(fd < 0)) - return -EINVAL; - - if ((unsigned int) fd > watch_entries - 1) - return -ERANGE; - - data = watch_list[fd]; - if (!data) - return -ENXIO; - - if (data->events == events && !force) - return 0; - - memset(&ev, 0, sizeof(ev)); - ev.events = events; - ev.data.ptr = data; - - err = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, data->fd, &ev); - if (err < 0) - return -errno; - - data->events = events; - - return 0; -} - -int watch_clear(int fd) -{ - struct watch_data *data; - - if (unlikely(fd < 0)) - return -EINVAL; - - if ((unsigned int) fd > watch_entries - 1) - return -ERANGE; - - data = watch_list[fd]; - if (!data) - return -ENXIO; - - watch_list[fd] = NULL; - - if (data->destroy) - data->destroy(data->user_data); - - if (data->flags & WATCH_FLAG_DISPATCHING) - data->flags |= WATCH_FLAG_DESTROYED; - else - l_free(data); - - return 0; -} - -int watch_remove(int fd) -{ - int err = watch_clear(fd); - - if (err < 0) - return err; - - err = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL); - if (err < 0) - return -errno; - - return err; -} - -static bool idle_remove_by_id(void *data, void *user_data) -{ - struct idle_data *idle = data; - int id = L_PTR_TO_INT(user_data); - - if (idle->id != id) - return false; - - if (idle->destroy) - idle->destroy(idle->user_data); - - if (idle->flags & IDLE_FLAG_DISPATCHING) { - idle->flags |= IDLE_FLAG_DESTROYED; - return false; - } - - l_free(idle); - - return true; -} - -static bool idle_prune(void *data, void *user_data) -{ - struct idle_data *idle = data; - - if ((idle->flags & IDLE_FLAG_DESTROYED) == 0) - return false; - - l_free(idle); - - return true; -} - -int idle_add(idle_event_cb_t callback, void *user_data, uint32_t flags, - idle_destroy_cb_t destroy) -{ - struct idle_data *data; - - if (unlikely(!callback)) - return -EINVAL; - - if (!epoll_fd) - return -EIO; - - data = l_new(struct idle_data, 1); - - data->callback = callback; - data->destroy = destroy; - data->user_data = user_data; - data->flags = flags; - - if (!l_queue_push_tail(idle_list, data)) { - l_free(data); - return -ENOMEM; - } - - data->id = idle_id++; - - if (idle_id == INT_MAX) - idle_id = 0; - - return data->id; -} - -void idle_remove(int id) -{ - l_queue_foreach_remove(idle_list, idle_remove_by_id, - L_INT_TO_PTR(id)); -} - -static void idle_destroy(void *data) -{ - struct idle_data *idle = data; - - if (!(idle->flags & IDLE_FLAG_NO_WARN_DANGLING)) - l_error("Dangling idle descriptor %p, %d found", - data, idle->id); - - if (idle->destroy) - idle->destroy(idle->user_data); - - l_free(idle); -} - -static void idle_dispatch(void *data, void *user_data) -{ - struct idle_data *idle = data; - - if (!idle->callback) - return; - - idle->flags |= IDLE_FLAG_DISPATCHING; - idle->callback(idle->user_data); - idle->flags &= ~IDLE_FLAG_DISPATCHING; -} - -static int sd_notify(const char *state) -{ - int err; - - if (notify_fd <= 0) - return -ENOTCONN; - - err = send(notify_fd, state, strlen(state), MSG_NOSIGNAL); - if (err < 0) - return -errno; - - return 0; -} - -static void watchdog_callback(struct l_timeout *timeout, void *user_data) -{ - int msec = L_PTR_TO_INT(user_data); - - sd_notify("WATCHDOG=1"); - - l_timeout_modify_ms(timeout, msec); -} - -static void create_sd_notify_socket(void) -{ - const char *sock; - struct sockaddr_un addr; - const char *watchdog_usec; - int msec; - - /* check if NOTIFY_SOCKET has been set */ - sock = getenv("NOTIFY_SOCKET"); - if (!sock) - return; - - /* check for abstract socket or absolute path */ - if (sock[0] != '@' && sock[0] != '/') - return; - - notify_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (notify_fd < 0) { - notify_fd = 0; - return; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, sock, sizeof(addr.sun_path) - 1); - - if (addr.sun_path[0] == '@') - addr.sun_path[0] = '\0'; - - if (bind(notify_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - close(notify_fd); - notify_fd = 0; - return; - } - - watchdog_usec = getenv("WATCHDOG_USEC"); - if (!watchdog_usec) - return; - - msec = atoi(watchdog_usec) / 1000; - if (msec < WATCHDOG_TRIGGER_FREQ) - return; - - msec /= WATCHDOG_TRIGGER_FREQ; - - watchdog = l_timeout_create_ms(msec, watchdog_callback, - L_INT_TO_PTR(msec), NULL); -} - -/** - * l_main_init: - * - * Initialize the main loop. This must be called before l_main_run() - * and any other function that directly or indirectly sets up an idle - * or watch. A safe rule-of-thumb is to call it before any function - * prefixed with "l_". - * - * Returns: true if initialization was successful, false otherwise. - **/ -LIB_EXPORT bool l_main_init(void) -{ - if (unlikely(epoll_running)) - return false; - - if (!create_epoll()) - return false; - - create_sd_notify_socket(); - - epoll_terminate = false; - - return true; -} - -/** - * l_main_prepare: - * - * Prepare the iteration of the main loop - * - * Returns: The timeout to use. This will be 0 if idle-event processing is - * currently pending, or -1 otherwise. This value can be used to pass to - * l_main_iterate. - */ -LIB_EXPORT int l_main_prepare(void) -{ - return l_queue_isempty(idle_list) ? -1 : 0; -} - -/** - * l_main_iterate: - * - * Run one iteration of the main event loop - */ -LIB_EXPORT void l_main_iterate(int timeout) -{ - struct epoll_event events[MAX_EPOLL_EVENTS]; - struct watch_data *data; - int n, nfds; - - nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, timeout); - - for (n = 0; n < nfds; n++) { - data = events[n].data.ptr; - - data->flags |= WATCH_FLAG_DISPATCHING; - } - - for (n = 0; n < nfds; n++) { - data = events[n].data.ptr; - - if (data->flags & WATCH_FLAG_DESTROYED) - continue; - - data->callback(data->fd, events[n].events, - data->user_data); - } - - for (n = 0; n < nfds; n++) { - data = events[n].data.ptr; - - if (data->flags & WATCH_FLAG_DESTROYED) - l_free(data); - else - data->flags = 0; - } - - l_queue_foreach(idle_list, idle_dispatch, NULL); - l_queue_foreach_remove(idle_list, idle_prune, NULL); -} - -/** - * l_main_run: - * - * Run the main loop - * - * The loop may be restarted by invoking this function after a - * previous invocation returns, provided that l_main_exit() has not - * been called first. - * - * Returns: #EXIT_SUCCESS after successful execution or #EXIT_FAILURE in - * case of failure - **/ -LIB_EXPORT int l_main_run(void) -{ - int timeout; - - /* Has l_main_init() been called? */ - if (unlikely(!epoll_fd)) - return EXIT_FAILURE; - - if (unlikely(epoll_running)) - return EXIT_FAILURE; - - epoll_running = true; - - for (;;) { - if (epoll_terminate) - break; - - timeout = l_main_prepare(); - l_main_iterate(timeout); - } - - epoll_running = false; - - if (notify_fd) { - close(notify_fd); - notify_fd = 0; - l_timeout_remove(watchdog); - watchdog = NULL; - } - - return EXIT_SUCCESS; -} - -/** - * l_main_exit: - * - * Clean up after main loop completes. - * - **/ -LIB_EXPORT bool l_main_exit(void) -{ - unsigned int i; - - if (epoll_running) { - l_error("Cleanup attempted on running main loop"); - return false; - } - - for (i = 0; i < watch_entries; i++) { - struct watch_data *data = watch_list[i]; - - if (!data) - continue; - - epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL); - - if (data->destroy) - data->destroy(data->user_data); - else - l_error("Dangling file descriptor %d found", data->fd); - - l_free(data); - } - - watch_entries = 0; - - free(watch_list); - watch_list = NULL; - - l_queue_destroy(idle_list, idle_destroy); - idle_list = NULL; - - close(epoll_fd); - epoll_fd = 0; - - return true; -} - -/** - * l_main_quit: - * - * Teminate the running main loop - * - * Returns: #true when terminating the main loop or #false in case of failure - **/ -LIB_EXPORT bool l_main_quit(void) -{ - if (unlikely(!epoll_running)) - return false; - - epoll_terminate = true; - - return true; -} - -struct signal_data { - l_main_signal_cb_t callback; - void *user_data; -}; - -static void sigint_handler(void *user_data) -{ - struct signal_data *data = user_data; - - if (data->callback) - data->callback(SIGINT, data->user_data); -} - -static void sigterm_handler(void *user_data) -{ - struct signal_data *data = user_data; - - if (data->callback) - data->callback(SIGTERM, data->user_data); -} - -/** - * l_main_run_with_signal: - * - * Run the main loop with signal handling for SIGINT and SIGTERM - * - * Returns: #EXIT_SUCCESS after successful execution or #EXIT_FAILURE in - * case of failure - **/ -LIB_EXPORT int l_main_run_with_signal(l_main_signal_cb_t callback, - void *user_data) -{ - struct signal_data *data; - struct l_signal *sigint; - struct l_signal *sigterm; - int result; - - data = l_new(struct signal_data, 1); - - data->callback = callback; - data->user_data = user_data; - - sigint = l_signal_create(SIGINT, sigint_handler, data, NULL); - sigterm = l_signal_create(SIGTERM, sigterm_handler, data, NULL); - - result = l_main_run(); - - l_signal_remove(sigint); - l_signal_remove(sigterm); - - l_free(data); - - return result; -} - -/** - * l_main_get_epoll_fd: - * - * Can be used to obtain the epoll file descriptor in order to integrate - * the ell main event loop with other event loops. - * - * Returns: epoll file descriptor - **/ -LIB_EXPORT int l_main_get_epoll_fd(void) -{ - return epoll_fd; -} diff --git a/ell/main.h b/ell/main.h deleted file mode 100644 index 99b34ad..0000000 --- a/ell/main.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_MAIN_H -#define __ELL_MAIN_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -bool l_main_init(void); -int l_main_prepare(void); -void l_main_iterate(int timeout); -int l_main_run(void); -bool l_main_exit(void); - -bool l_main_quit(void); - -typedef void (*l_main_signal_cb_t) (uint32_t signo, void *user_data); - -int l_main_run_with_signal(l_main_signal_cb_t callback, void *user_data); - -int l_main_get_epoll_fd(); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_MAIN_H */ diff --git a/ell/missing.h b/ell/missing.h deleted file mode 100644 index 37d5586..0000000 --- a/ell/missing.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include - -#ifndef __NR_getrandom -# if defined __x86_64__ -# define __NR_getrandom 318 -# elif defined(__i386__) -# define __NR_getrandom 355 -# elif defined(__arm__) -# define __NR_getrandom 384 -# elif defined(__aarch64__) -# define __NR_getrandom 278 -# elif defined(__ia64__) -# define __NR_getrandom 1339 -# elif defined(__m68k__) -# define __NR_getrandom 352 -# elif defined(__s390x__) -# define __NR_getrandom 349 -# elif defined(__powerpc__) -# define __NR_getrandom 359 -# elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define __NR_getrandom 4353 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_getrandom 6317 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_getrandom 5313 -# endif -# else -# warning "__NR_getrandom unknown for your architecture" -# define __NR_getrandom 0xffffffff -# endif -#endif - -#ifndef HAVE_EXPLICIT_BZERO -static inline void explicit_bzero(void *s, size_t n) -{ - memset(s, 0, n); - __asm__ __volatile__ ("" : : "r"(s) : "memory"); -} -#endif diff --git a/ell/net.c b/ell/net.c deleted file mode 100644 index b5b5f9d..0000000 --- a/ell/net.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "net.h" -#include "private.h" - -/** - * SECTION:net - * @short_description: Network Interface related utilities - * - * Network Interface utilities - */ - -/** - * l_net_get_mac_address: - * @ifindex: Interface index to query - * @out_addr: Buffer to copy the mac address to. Must be able to hold 6 bytes - * - * Obtains the mac address of the network interface given by @ifindex - * - * Returns: #true on success and #false on failure - **/ -LIB_EXPORT bool l_net_get_mac_address(uint32_t ifindex, uint8_t *out_addr) -{ - struct ifreq ifr; - int sk, err; - - sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (sk < 0) - return false; - - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_ifindex = ifindex; - - err = ioctl(sk, SIOCGIFNAME, &ifr); - if (err < 0) - goto error; - - err = ioctl(sk, SIOCGIFHWADDR, &ifr); - if (err < 0) - goto error; - - close(sk); - - if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) - return false; - - memcpy(out_addr, ifr.ifr_hwaddr.sa_data, 6); - return true; - -error: - close(sk); - return false; -} - -/** - * l_net_get_name: - * @ifindex: Interface index to query - * - * Obtains the name of the network inderface given by @ifindex - * - * Returns: A newly allocated string with the name or NULL on failure - **/ -LIB_EXPORT char *l_net_get_name(uint32_t ifindex) -{ - struct ifreq ifr; - int sk, err; - - sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (sk < 0) - return NULL; - - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_ifindex = ifindex; - - err = ioctl(sk, SIOCGIFNAME, &ifr); - close(sk); - - if (err < 0) - return NULL; - - return l_strdup(ifr.ifr_name); -} diff --git a/ell/net.h b/ell/net.h deleted file mode 100644 index 25b1ca2..0000000 --- a/ell/net.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_NET_H -#define __ELL_NET_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -bool l_net_get_mac_address(uint32_t ifindex, uint8_t *out_addr); -char *l_net_get_name(uint32_t ifindex); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_NET_H */ diff --git a/ell/netlink-private.h b/ell/netlink-private.h deleted file mode 100644 index fff30af..0000000 --- a/ell/netlink-private.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef SOL_NETLINK -#define SOL_NETLINK 270 -#endif diff --git a/ell/netlink.c b/ell/netlink.c deleted file mode 100644 index 33d0e5b..0000000 --- a/ell/netlink.c +++ /dev/null @@ -1,613 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "util.h" -#include "hashmap.h" -#include "queue.h" -#include "io.h" -#include "netlink-private.h" -#include "netlink.h" -#include "private.h" - -struct command { - unsigned int id; - uint32_t seq; - uint32_t len; - l_netlink_command_func_t handler; - l_netlink_destroy_func_t destroy; - void *user_data; -}; - -struct notify { - uint32_t group; - l_netlink_notify_func_t handler; - l_netlink_destroy_func_t destroy; - void *user_data; -}; - -struct l_netlink { - uint32_t pid; - struct l_io *io; - uint32_t next_seq; - struct l_queue *command_queue; - struct l_hashmap *command_pending; - struct l_hashmap *command_lookup; - unsigned int next_command_id; - struct l_hashmap *notify_groups; - struct l_hashmap *notify_lookup; - unsigned int next_notify_id; - l_netlink_debug_func_t debug_handler; - l_netlink_destroy_func_t debug_destroy; - void *debug_data; -}; - -static void destroy_command(void *data) -{ - struct command *command = data; - - if (command->destroy) - command->destroy(command->user_data); - - l_free(command); -} - -static void destroy_notify(void *data) -{ - struct notify *notify = data; - - if (notify->destroy) - notify->destroy(notify->user_data); - - l_free(notify); -} - -static void destroy_notify_group(void *data) -{ - struct l_hashmap *notify_list = data; - - l_hashmap_destroy(notify_list, destroy_notify); -} - -static bool can_write_data(struct l_io *io, void *user_data) -{ - struct l_netlink *netlink = user_data; - struct command *command; - struct sockaddr_nl addr; - const void *data; - ssize_t written; - int sk; - - command = l_queue_pop_head(netlink->command_queue); - if (!command) - return false; - - sk = l_io_get_fd(io); - - memset(&addr, 0, sizeof(addr)); - addr.nl_family = AF_NETLINK; - addr.nl_pid = 0; - - data = ((void *) command) + NLMSG_ALIGN(sizeof(struct command)); - - written = sendto(sk, data, command->len, 0, - (struct sockaddr *) &addr, sizeof(addr)); - if (written < 0 || (uint32_t) written != command->len) { - l_hashmap_remove(netlink->command_lookup, - L_UINT_TO_PTR(command->id)); - destroy_command(command); - return true; - } - - l_util_hexdump(false, data, command->len, - netlink->debug_handler, netlink->debug_data); - - l_hashmap_insert(netlink->command_pending, - L_UINT_TO_PTR(command->seq), command); - - return l_queue_length(netlink->command_queue) > 0; -} - -static void do_notify(const void *key, void *value, void *user_data) -{ - struct nlmsghdr *nlmsg = user_data; - struct notify *notify = value; - - if (notify->handler) { - notify->handler(nlmsg->nlmsg_type, NLMSG_DATA(nlmsg), - nlmsg->nlmsg_len - NLMSG_HDRLEN, notify->user_data); - } -} - -static void process_broadcast(struct l_netlink *netlink, uint32_t group, - struct nlmsghdr *nlmsg) -{ - struct l_hashmap *notify_list; - - notify_list = l_hashmap_lookup(netlink->notify_groups, - L_UINT_TO_PTR(group)); - if (!notify_list) - return; - - l_hashmap_foreach(notify_list, do_notify, nlmsg); -} - -static void process_message(struct l_netlink *netlink, struct nlmsghdr *nlmsg) -{ - const void *data = nlmsg; - struct command *command; - - command = l_hashmap_remove(netlink->command_pending, - L_UINT_TO_PTR(nlmsg->nlmsg_seq)); - if (!command) - return; - - if (!command->handler) - goto done; - - if (nlmsg->nlmsg_type < NLMSG_MIN_TYPE) { - const struct nlmsgerr *err; - - switch (nlmsg->nlmsg_type) { - case NLMSG_ERROR: - err = data + NLMSG_HDRLEN; - - command->handler(err->error, 0, NULL, 0, - command->user_data); - break; - } - } else { - command->handler(0, nlmsg->nlmsg_type, data + NLMSG_HDRLEN, - nlmsg->nlmsg_len - NLMSG_HDRLEN, - command->user_data); - } - -done: - l_hashmap_remove(netlink->command_lookup, L_UINT_TO_PTR(command->id)); - - destroy_command(command); -} - -static void process_multi(struct l_netlink *netlink, struct nlmsghdr *nlmsg) -{ - const void *data = nlmsg; - struct command *command; - - if (nlmsg->nlmsg_type < NLMSG_MIN_TYPE) { - command = l_hashmap_remove(netlink->command_pending, - L_UINT_TO_PTR(nlmsg->nlmsg_seq)); - if (!command) - return; - - l_hashmap_remove(netlink->command_lookup, - L_UINT_TO_PTR(command->id)); - - destroy_command(command); - } else { - command = l_hashmap_lookup(netlink->command_pending, - L_UINT_TO_PTR(nlmsg->nlmsg_seq)); - if (!command) - return; - - if (!command->handler) - return; - - command->handler(0, nlmsg->nlmsg_type, data + NLMSG_HDRLEN, - nlmsg->nlmsg_len - NLMSG_HDRLEN, - command->user_data); - } -} - -static bool can_read_data(struct l_io *io, void *user_data) -{ - struct l_netlink *netlink = user_data; - struct cmsghdr *cmsg; - struct msghdr msg; - struct iovec iov; - struct nlmsghdr *nlmsg; - unsigned char buffer[4096]; - unsigned char control[32]; - uint32_t group = 0; - ssize_t len; - int sk; - - memset(buffer, 0, sizeof(buffer)); - memset(control, 0, sizeof(control)); - - sk = l_io_get_fd(io); - - iov.iov_base = buffer; - iov.iov_len = sizeof(buffer); - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = control; - msg.msg_controllen = sizeof(control); - - len = recvmsg(sk, &msg, 0); - if (len < 0) - return false; - - l_util_hexdump(true, buffer, len, netlink->debug_handler, - netlink->debug_data); - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - struct nl_pktinfo *pktinfo; - - if (cmsg->cmsg_level != SOL_NETLINK) - continue; - - if (cmsg->cmsg_type != NETLINK_PKTINFO) - continue; - - pktinfo = (void *) CMSG_DATA(cmsg); - - group = pktinfo->group; - } - - for (nlmsg = iov.iov_base; NLMSG_OK(nlmsg, (uint32_t) len); - nlmsg = NLMSG_NEXT(nlmsg, len)) { - if (group > 0) { - process_broadcast(netlink, group, nlmsg); - continue; - } - - if (nlmsg->nlmsg_pid != netlink->pid) - continue; - - if (nlmsg->nlmsg_flags & NLM_F_MULTI) - process_multi(netlink, nlmsg); - else - process_message(netlink, nlmsg); - } - - return true; -} - -static int create_netlink_socket(int protocol, uint32_t *pid) -{ - struct sockaddr_nl addr; - socklen_t addrlen = sizeof(addr); - int sk, pktinfo = 1; - - sk = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - protocol); - if (sk < 0) - return -1; - - memset(&addr, 0, sizeof(addr)); - addr.nl_family = AF_NETLINK; - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - close(sk); - return -1; - } - - if (getsockname(sk, (struct sockaddr *) &addr, &addrlen) < 0) { - close(sk); - return -1; - } - - if (setsockopt(sk, SOL_NETLINK, NETLINK_PKTINFO, - &pktinfo, sizeof(pktinfo)) < 0) { - close(sk); - return -1; - } - - if (pid) - *pid = addr.nl_pid; - - return sk; -} - -LIB_EXPORT struct l_netlink *l_netlink_new(int protocol) -{ - struct l_netlink *netlink; - int sk; - - netlink = l_new(struct l_netlink, 1); - - netlink->next_seq = 1; - netlink->next_command_id = 1; - netlink->next_notify_id = 1; - - sk = create_netlink_socket(protocol, &netlink->pid); - if (sk < 0) { - l_free(netlink); - return NULL; - } - - netlink->io = l_io_new(sk); - if (!netlink->io) { - close(sk); - l_free(netlink); - return NULL; - } - - l_io_set_close_on_destroy(netlink->io, true); - - l_io_set_read_handler(netlink->io, can_read_data, netlink, NULL); - - netlink->command_queue = l_queue_new(); - netlink->command_pending = l_hashmap_new(); - netlink->command_lookup = l_hashmap_new(); - - netlink->notify_groups = l_hashmap_new(); - netlink->notify_lookup = l_hashmap_new(); - - return netlink; -} - -LIB_EXPORT void l_netlink_destroy(struct l_netlink *netlink) -{ - if (unlikely(!netlink)) - return; - - l_hashmap_destroy(netlink->notify_lookup, NULL); - l_hashmap_destroy(netlink->notify_groups, destroy_notify_group); - - l_queue_destroy(netlink->command_queue, NULL); - l_hashmap_destroy(netlink->command_pending, NULL); - l_hashmap_destroy(netlink->command_lookup, destroy_command); - - l_io_destroy(netlink->io); - - l_free(netlink); -} - -LIB_EXPORT unsigned int l_netlink_send(struct l_netlink *netlink, - uint16_t type, uint16_t flags, const void *data, - uint32_t len, l_netlink_command_func_t function, - void *user_data, l_netlink_destroy_func_t destroy) -{ - struct command *command; - struct nlmsghdr *nlmsg; - size_t size; - - if (unlikely(!netlink)) - return 0; - - if (!netlink->command_queue || !netlink->command_pending || - !netlink->command_lookup) - return 0; - - if (flags & 0xff) - return 0; - - if (function) - flags |= NLM_F_ACK; - - size = NLMSG_ALIGN(sizeof(struct command)) + - NLMSG_HDRLEN + NLMSG_ALIGN(len); - - command = l_malloc(size); - - memset(command, 0, size); - command->handler = function; - command->destroy = destroy; - command->user_data = user_data; - - command->id = netlink->next_command_id; - - if (!l_hashmap_insert(netlink->command_lookup, - L_UINT_TO_PTR(command->id), command)) - goto free_command; - - command->seq = netlink->next_seq++; - command->len = NLMSG_HDRLEN + NLMSG_ALIGN(len); - - nlmsg = ((void *) command) + NLMSG_ALIGN(sizeof(struct command)); - - nlmsg->nlmsg_len = command->len; - nlmsg->nlmsg_type = type; - nlmsg->nlmsg_flags = NLM_F_REQUEST | flags; - nlmsg->nlmsg_seq = command->seq; - nlmsg->nlmsg_pid = netlink->pid; - - if (data && len > 0) - memcpy(((void *) nlmsg) + NLMSG_HDRLEN, data, len); - - l_queue_push_tail(netlink->command_queue, command); - - l_io_set_write_handler(netlink->io, can_write_data, netlink, NULL); - - netlink->next_command_id++; - - return command->id; - -free_command: - l_free(command); - - return 0; -} - -LIB_EXPORT bool l_netlink_cancel(struct l_netlink *netlink, unsigned int id) -{ - struct command *command; - - if (unlikely(!netlink || !id)) - return false; - - if (!netlink->command_queue || !netlink->command_pending || - !netlink->command_lookup) - return false; - - command = l_hashmap_remove(netlink->command_lookup, L_UINT_TO_PTR(id)); - if (!command) - return false; - - if (!l_queue_remove(netlink->command_queue, command)) { - l_hashmap_remove(netlink->command_pending, - L_UINT_TO_PTR(command->seq)); - } - - destroy_command(command); - - return true; -} - -static bool add_membership(struct l_netlink *netlink, uint32_t group) -{ - int sk, value = group; - - sk = l_io_get_fd(netlink->io); - - if (setsockopt(sk, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, - &value, sizeof(value)) < 0) - return false; - - return true; -} - -static bool drop_membership(struct l_netlink *netlink, uint32_t group) -{ - int sk, value = group; - - sk = l_io_get_fd(netlink->io); - - if (setsockopt(sk, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, - &value, sizeof(value)) < 0) - return false; - - return true; -} - -LIB_EXPORT unsigned int l_netlink_register(struct l_netlink *netlink, - uint32_t group, l_netlink_notify_func_t function, - void *user_data, l_netlink_destroy_func_t destroy) -{ - struct l_hashmap *notify_list; - struct notify *notify; - unsigned int id; - - if (unlikely(!netlink)) - return 0; - - if (!netlink->notify_groups || !netlink->notify_lookup) - return 0; - - notify_list = l_hashmap_lookup(netlink->notify_groups, - L_UINT_TO_PTR(group)); - if (!notify_list) { - notify_list = l_hashmap_new(); - if (!notify_list) - return 0; - - if (!l_hashmap_insert(netlink->notify_groups, - L_UINT_TO_PTR(group), notify_list)) { - l_hashmap_destroy(notify_list, NULL); - return 0; - } - } - - notify = l_new(struct notify, 1); - - notify->group = group; - notify->handler = function; - notify->destroy = destroy; - notify->user_data = user_data; - - id = netlink->next_notify_id; - - if (!l_hashmap_insert(netlink->notify_lookup, - L_UINT_TO_PTR(id), notify_list)) - goto free_notify; - - if (!l_hashmap_insert(notify_list, L_UINT_TO_PTR(id), notify)) - goto remove_lookup; - - if (l_hashmap_size(notify_list) == 1) { - if (!add_membership(netlink, notify->group)) - goto remove_notify; - } - - netlink->next_notify_id++; - - return id; - -remove_notify: - l_hashmap_remove(notify_list, L_UINT_TO_PTR(id)); - -remove_lookup: - l_hashmap_remove(netlink->notify_lookup, L_UINT_TO_PTR(id)); - -free_notify: - l_free(notify); - - return 0; -} - -LIB_EXPORT bool l_netlink_unregister(struct l_netlink *netlink, unsigned int id) -{ - struct l_hashmap *notify_list; - struct notify *notify; - - if (unlikely(!netlink || !id)) - return false; - - if (!netlink->notify_groups || !netlink->notify_lookup) - return false; - - notify_list = l_hashmap_remove(netlink->notify_lookup, - L_UINT_TO_PTR(id)); - if (!notify_list) - return false; - - notify = l_hashmap_remove(notify_list, L_UINT_TO_PTR(id)); - if (!notify) - return false; - - if (l_hashmap_size(notify_list) == 0) - drop_membership(netlink, notify->group); - - destroy_notify(notify); - - return true; -} - -LIB_EXPORT bool l_netlink_set_debug(struct l_netlink *netlink, - l_netlink_debug_func_t function, - void *user_data, l_netlink_destroy_func_t destroy) -{ - if (unlikely(!netlink)) - return false; - - if (netlink->debug_destroy) - netlink->debug_destroy(netlink->debug_data); - - netlink->debug_handler = function; - netlink->debug_destroy = destroy; - netlink->debug_data = user_data; - - /* l_io_set_debug(netlink->io, function, user_data, NULL); */ - - return true; -} diff --git a/ell/netlink.h b/ell/netlink.h deleted file mode 100644 index b40933f..0000000 --- a/ell/netlink.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_NETLINK_H -#define __ELL_NETLINK_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*l_netlink_debug_func_t) (const char *str, void *user_data); - -typedef void (*l_netlink_command_func_t) (int error, - uint16_t type, const void *data, - uint32_t len, void *user_data); -typedef void (*l_netlink_notify_func_t) (uint16_t type, const void *data, - uint32_t len, void *user_data); -typedef void (*l_netlink_destroy_func_t) (void *user_data); - -struct l_netlink; - -struct l_netlink *l_netlink_new(int protocol); -void l_netlink_destroy(struct l_netlink *netlink); - -unsigned int l_netlink_send(struct l_netlink *netlink, - uint16_t type, uint16_t flags, const void *data, - uint32_t len, l_netlink_command_func_t function, - void *user_data, l_netlink_destroy_func_t destroy); -bool l_netlink_cancel(struct l_netlink *netlink, unsigned int id); - -unsigned int l_netlink_register(struct l_netlink *netlink, - uint32_t group, l_netlink_notify_func_t function, - void *user_data, l_netlink_destroy_func_t destroy); -bool l_netlink_unregister(struct l_netlink *netlink, unsigned int id); - -bool l_netlink_set_debug(struct l_netlink *netlink, - l_netlink_debug_func_t function, - void *user_data, l_netlink_destroy_func_t destroy); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_NETLINK_H */ diff --git a/ell/path.c b/ell/path.c deleted file mode 100644 index dfede14..0000000 --- a/ell/path.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include -#include -#include - -#include "time.h" -#include "path.h" -#include "private.h" - -static const char *next_in_path(const char *path, char **ret, size_t overhead) -{ - const char *p = path; - char *r; - size_t toalloc = 0; - - while (p[0] != '\0' && p[0] != ':') { - switch (*p) { - case '\\': - if (!*++p) - break; - /* Fall through */ - default: - p++; - toalloc += 1; - break; - } - } - - r = l_new(char, toalloc + 1 + overhead); - p = path; - *ret = r; - - while (p[0] != '\0' && p[0] != ':') { - switch (*p) { - case '\\': - if (!*++p) - break; - /* Fall through */ - default: - *r++ = *p++; - break; - } - } - - if (p[0] == ':') - p++; - - return p; -} - -/** - * l_path_next: - * @path_str: contents of $PATH-like string - * @ret: The returned value - * - * Attempts to parse the next element of a $PATH-like string and returns the - * resulting directory in a newly-allocated variable assigned to @ret. @ret - * must be a valid pointer to a char *. - * - * Returns: A pointer inside @path_str that begins just past the next ':' - * delimiter character or to the end of the string. - **/ -LIB_EXPORT const char *l_path_next(const char *path_str, char **ret) -{ - if (unlikely(!path_str)) - return NULL; - - return next_in_path(path_str, ret, 0); -} - -/** - * l_path_find: - * @basename: The basename of the file, e.g. "vi" - * @path_str: A list of paths formatted like $PATH, e.g. from getenv - * @mode: mode to check. This is the same mode as would be fed to access() - * - * Attempts to find @basename in one of the directories listed in @path_str. - * Only directories with absolute paths are used. - * - * Returns: A newly-allocated string with the full path of the resolved file - * given by @basename. E.g. /usr/bin/vi. Or NULL if no file could be found - * that matches the given @mode. - */ -LIB_EXPORT char *l_path_find(const char *basename, - const char *path_str, int mode) -{ - size_t overhead; - size_t len; - char *path; - - if (unlikely(!path_str || !basename)) - return NULL; - - overhead = strlen(basename) + 1; - - do { - path_str = next_in_path(path_str, &path, overhead); - - if (path[0] == '/') { - len = strlen(path); - - if (path[len - 1] != '/') - path[len++] = '/'; - - strcpy(path + len, basename); - - if (access(path, mode) == 0) - return path; - } - - l_free(path); - } while (path_str[0] != '\0'); - - return NULL; -} - -/** - * l_path_get_mtime: - * @path: The path of the file - * - * Attempts find the modified time of file pointed to by @path. If @path - * is a symbolic link, then the link is followed. - * - * Returns: The number of microseconds (usec) since the Epoch or L_TIME_INVALID - * if an error occurred. - */ -LIB_EXPORT uint64_t l_path_get_mtime(const char *path) -{ - struct stat sb; - int ret; - - if (unlikely(path == NULL)) - return L_TIME_INVALID; - - ret = stat(path, &sb); - if (ret < 0) - return L_TIME_INVALID; - - return sb.st_mtim.tv_sec * 1000000 + sb.st_mtim.tv_nsec / 1000; -} - -/** - * l_path_touch: - * @path: The path of the file - * - * Updates the modification and last_accessed time of the file given by @path - * to the current time. If @path is a symbolic link, then the link is followed. - * - * Returns: 0 if the file times could be updated successfully and -errno - * otherwise. - */ -LIB_EXPORT int l_path_touch(const char *path) -{ - if (unlikely(!path)) - return -EINVAL; - - if (utimensat(0, path, NULL, 0) == 0) - return 0; - - return -errno; -} diff --git a/ell/path.h b/ell/path.h deleted file mode 100644 index c89af32..0000000 --- a/ell/path.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_PATH_H -#define __ELL_PATH_H - -#ifdef __cplusplus -extern "C" { -#endif - -const char *l_path_next(const char *path_str, char **ret); -char *l_path_find(const char *basename, const char *path_str, int mode); -uint64_t l_path_get_mtime(const char *path); -int l_path_touch(const char *path); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_PATH_H */ diff --git a/ell/pem-private.h b/ell/pem-private.h deleted file mode 100644 index eadc115..0000000 --- a/ell/pem-private.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include - -const char *pem_next(const void *buf, size_t buf_len, char **type_label, - size_t *base64_len, - const char **endp, bool strict); diff --git a/ell/pem.c b/ell/pem.c deleted file mode 100644 index edf6bb0..0000000 --- a/ell/pem.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2015 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "private.h" -#include "key.h" -#include "cert.h" -#include "queue.h" -#include "pem.h" -#include "base64.h" -#include "utf8.h" -#include "asn1-private.h" -#include "pkcs5-private.h" -#include "cipher.h" -#include "cert-private.h" -#include "missing.h" -#include "pem-private.h" - -#define PEM_START_BOUNDARY "-----BEGIN " -#define PEM_END_BOUNDARY "-----END " - -static const char *is_start_boundary(const void *buf, size_t buf_len, - size_t *label_len) -{ - const char *start, *end, *ptr; - int prev_special, special; - const char *buf_ptr = buf; - - if (buf_len < strlen(PEM_START_BOUNDARY)) - return NULL; - - /* Check we have a "-----BEGIN " (RFC7468 section 2) */ - if (memcmp(buf, PEM_START_BOUNDARY, strlen(PEM_START_BOUNDARY))) - return NULL; - - /* - * Check we have a string of printable characters in which no - * two consecutive characters are "special" nor is the first or the - * final character "special". These special characters are space - * and hyphen. (RFC7468 section 3) - * The loop will end on the second hyphen of the final "-----" if - * no error found earlier. - */ - start = buf + strlen(PEM_START_BOUNDARY); - end = start; - prev_special = 1; - - while (end < buf_ptr + buf_len && l_ascii_isprint(*end)) { - special = *end == ' ' || *end == '-'; - - if (prev_special && special) - break; - - end++; - prev_special = special; - } - - /* Rewind to the first '-', but handle empty labels */ - if (end != start) - end--; - - /* Check we have a "-----" (RFC7468 section 2) */ - if (end + 5 > buf_ptr + buf_len || memcmp(end, "-----", 5)) - return NULL; - - /* Check all remaining characters are horizontal whitespace (WSP) */ - for (ptr = end + 5; ptr < buf_ptr + buf_len; ptr++) - if (*ptr != ' ' && *ptr != '\t') - return NULL; - - *label_len = end - start; - - return start; -} - -static bool is_end_boundary(const void *buf, size_t buf_len, - const char *label, size_t label_len) -{ - const char *buf_ptr = buf; - size_t len = strlen(PEM_END_BOUNDARY) + label_len + 5; - - if (buf_len < len) - return false; - - if (memcmp(buf_ptr, PEM_END_BOUNDARY, strlen(PEM_END_BOUNDARY)) || - memcmp(buf_ptr + strlen(PEM_END_BOUNDARY), - label, label_len) || - memcmp(buf_ptr + (len - 5), "-----", 5)) - return false; - - /* Check all remaining characters are horizontal whitespace (WSP) */ - for (; len < buf_len; len++) - if (buf_ptr[len] != ' ' && buf_ptr[len] != '\t') - return false; - - return true; -} - -const char *pem_next(const void *buf, size_t buf_len, char **type_label, - size_t *base64_len, - const char **endp, bool strict) -{ - const char *buf_ptr = buf; - const char *base64_data = NULL, *eol; - const char *label = NULL; - size_t label_len = 0; - const char *start = NULL; - - /* - * The base64 parser uses the RFC7468 laxbase64text grammar but we - * do full checks on the encapsulation boundary lines, i.e. no - * leading spaces allowed, making sure quoted text and similar - * are not confused for actual PEM "textual encoding". - */ - while (buf_len) { - for (eol = buf_ptr; eol < buf_ptr + buf_len; eol++) - if (*eol == '\r' || *eol == '\n') - break; - - if (!base64_data) { - label = is_start_boundary(buf_ptr, eol - buf_ptr, - &label_len); - if (label) { - start = label - strlen("-----BEGIN "); - base64_data = eol; - } else if (strict) - break; - } else if (start && is_end_boundary(buf_ptr, eol - buf_ptr, - label, label_len)) { - if (type_label) - *type_label = l_strndup(label, label_len); - - if (base64_len) - *base64_len = buf_ptr - base64_data; - - if (endp) { - if (eol == buf + buf_len) - *endp = eol; - else - *endp = eol + 1; - } - - return base64_data; - } - - if (eol == buf_ptr + buf_len) - break; - - buf_len -= eol + 1 - buf_ptr; - buf_ptr = eol + 1; - - if (buf_len && *eol == '\r' && *buf_ptr == '\n') { - buf_ptr++; - buf_len--; - } - } - - /* If we found no label signal EOF rather than parse error */ - if (!base64_data && endp) - *endp = NULL; - - return NULL; -} - -static uint8_t *pem_load_buffer(const void *buf, size_t buf_len, - char **type_label, size_t *len) -{ - size_t base64_len; - const char *base64; - char *label; - uint8_t *ret; - - base64 = pem_next(buf, buf_len, &label, &base64_len, - NULL, false); - if (!base64) - return NULL; - - ret = l_base64_decode(base64, base64_len, len); - if (ret) { - *type_label = label; - return ret; - } - - l_free(label); - - return NULL; -} - -LIB_EXPORT uint8_t *l_pem_load_buffer(const void *buf, size_t buf_len, - char **type_label, size_t *out_len) -{ - return pem_load_buffer(buf, buf_len, type_label, out_len); -} - -struct pem_file_info { - int fd; - struct stat st; - uint8_t *data; -}; - -static int pem_file_open(struct pem_file_info *info, const char *filename) -{ - info->fd = open(filename, O_RDONLY); - if (info->fd < 0) - return -errno; - - if (fstat(info->fd, &info->st) < 0) { - int r = -errno; - - close(info->fd); - return r; - } - - info->data = mmap(NULL, info->st.st_size, - PROT_READ, MAP_SHARED, info->fd, 0); - if (info->data == MAP_FAILED) { - int r = -errno; - - close(info->fd); - return r; - } - - return 0; -} - -static void pem_file_close(struct pem_file_info *info) -{ - munmap(info->data, info->st.st_size); - close(info->fd); -} - -LIB_EXPORT uint8_t *l_pem_load_file(const char *filename, - char **type_label, size_t *len) -{ - struct pem_file_info file; - uint8_t *result; - - if (unlikely(!filename)) - return NULL; - - if (pem_file_open(&file, filename) < 0) - return NULL; - - result = pem_load_buffer(file.data, file.st.st_size, - type_label, len); - pem_file_close(&file); - return result; -} - -static struct l_certchain *pem_list_to_chain(struct l_queue *list) -{ - struct l_certchain *chain; - - if (!list) - return NULL; - - chain = certchain_new_from_leaf(l_queue_pop_head(list)); - - while (!l_queue_isempty(list)) - certchain_link_issuer(chain, l_queue_pop_head(list)); - - l_queue_destroy(list, NULL); - return chain; -} - -LIB_EXPORT struct l_certchain *l_pem_load_certificate_chain_from_data( - const void *buf, size_t len) -{ - struct l_queue *list = l_pem_load_certificate_list_from_data(buf, len); - - if (!list) - return NULL; - - return pem_list_to_chain(list); -} - -LIB_EXPORT struct l_certchain *l_pem_load_certificate_chain( - const char *filename) -{ - struct l_queue *list = l_pem_load_certificate_list(filename); - - if (!list) - return NULL; - - return pem_list_to_chain(list); -} - -LIB_EXPORT struct l_queue *l_pem_load_certificate_list_from_data( - const void *buf, size_t len) -{ - const char *ptr, *end; - struct l_queue *list = NULL; - - ptr = buf; - end = buf + len; - - while (ptr && ptr < end) { - uint8_t *der; - size_t der_len; - char *label = NULL; - struct l_cert *cert; - const char *base64; - size_t base64_len; - - base64 = pem_next(ptr, len, &label, &base64_len, &ptr, false); - if (!base64) { - if (!ptr) - break; - - /* if ptr was not reset to NULL; parse error */ - goto error; - } - - der = l_base64_decode(base64, base64_len, &der_len); - - if (!der || strcmp(label, "CERTIFICATE")) { - if (der) - l_free(label); - l_free(der); - - goto error; - } - - l_free(label); - cert = l_cert_new_from_der(der, der_len); - l_free(der); - - if (!cert) - goto error; - - if (!list) - list = l_queue_new(); - - l_queue_push_tail(list, cert); - } - - return list; - -error: - l_queue_destroy(list, (l_queue_destroy_func_t) l_cert_free); - return NULL; -} - -LIB_EXPORT struct l_queue *l_pem_load_certificate_list(const char *filename) -{ - struct pem_file_info file; - struct l_queue *list = NULL; - - if (unlikely(!filename)) - return NULL; - - if (pem_file_open(&file, filename) < 0) - return NULL; - - list = l_pem_load_certificate_list_from_data(file.data, - file.st.st_size); - pem_file_close(&file); - - return list; -} - -static struct l_key *pem_load_private_key(uint8_t *content, - size_t len, - char *label, - const char *passphrase, - bool *encrypted) -{ - struct l_key *pkey = NULL; - - /* - * RFC7469- and PKCS#8-compatible label (default in OpenSSL 1.0.1+) - * and the older (OpenSSL <= 0.9.8 default) label. - */ - if (!strcmp(label, "PRIVATE KEY") || - !strcmp(label, "RSA PRIVATE KEY")) - goto done; - - /* RFC5958 (PKCS#8) section 3 type encrypted key label */ - if (!strcmp(label, "ENCRYPTED PRIVATE KEY")) { - const uint8_t *key_info, *alg_id, *data; - uint8_t tag; - size_t key_info_len, alg_id_len, data_len, tmp_len; - struct l_cipher *alg; - uint8_t *decrypted; - int i; - - if (encrypted) - *encrypted = true; - - if (!passphrase) - goto err; - - /* Technically this is BER, not limited to DER */ - key_info = asn1_der_find_elem(content, len, 0, &tag, - &key_info_len); - if (!key_info || tag != ASN1_ID_SEQUENCE) - goto err; - - alg_id = asn1_der_find_elem(key_info, key_info_len, 0, &tag, - &alg_id_len); - if (!alg_id || tag != ASN1_ID_SEQUENCE) - goto err; - - data = asn1_der_find_elem(key_info, key_info_len, 1, &tag, - &data_len); - if (!data || tag != ASN1_ID_OCTET_STRING || data_len < 8 || - (data_len & 7) != 0) - goto err; - - if (asn1_der_find_elem(content, len, 2, &tag, &tmp_len)) - goto err; - - alg = pkcs5_cipher_from_alg_id(alg_id, alg_id_len, passphrase); - if (!alg) - goto err; - - decrypted = l_malloc(data_len); - - if (!l_cipher_decrypt(alg, data, decrypted, data_len)) { - l_cipher_free(alg); - l_free(decrypted); - goto err; - } - - l_cipher_free(alg); - explicit_bzero(content, len); - l_free(content); - content = decrypted; - len = data_len; - - /* - * Strip padding as defined in RFC8018 (for PKCS#5 v1) or - * RFC1423 / RFC5652 (for v2). - */ - - if (content[data_len - 1] >= data_len || - content[data_len - 1] > 16) - goto err; - - for (i = 1; i < content[data_len - 1]; i++) - if (content[data_len - 1 - i] != content[data_len - 1]) - goto err; - - len = data_len - content[data_len - 1]; - - goto done; - } - - /* - * TODO: handle RSA PRIVATE KEY format encrypted keys - * (as produced by "openssl rsa" commands), incompatible with - * RFC7468 parsing because of the headers present before - * base64-encoded data. - */ - - /* Label not known */ - goto err; - -done: - pkey = l_key_new(L_KEY_RSA, content, len); - -err: - if (content) { - explicit_bzero(content, len); - l_free(content); - } - - l_free(label); - return pkey; -} - -LIB_EXPORT struct l_key *l_pem_load_private_key_from_data(const void *buf, - size_t buf_len, - const char *passphrase, - bool *encrypted) -{ - uint8_t *content; - char *label; - size_t len; - - if (encrypted) - *encrypted = false; - - content = pem_load_buffer(buf, buf_len, &label, &len); - - if (!content) - return NULL; - - return pem_load_private_key(content, len, label, passphrase, encrypted); -} - -/** - * l_pem_load_private_key - * @filename: path string to the PEM file to load - * @passphrase: private key encryption passphrase or NULL for unencrypted - * @encrypted: receives indication whether the file was encrypted if non-NULL - * - * Load the PEM encoded RSA Private Key file at @filename. If it is an - * encrypted private key and @passphrase was non-NULL, the file is - * decrypted. If it's unencrypted @passphrase is ignored. @encrypted - * stores information of whether the file was encrypted, both in a - * success case and on error when NULL is returned. This can be used to - * check if a passphrase is required without prior information. - * - * Returns: An l_key object to be freed with an l_key_free* function, - * or NULL. - **/ -LIB_EXPORT struct l_key *l_pem_load_private_key(const char *filename, - const char *passphrase, - bool *encrypted) -{ - uint8_t *content; - char *label; - size_t len; - - if (encrypted) - *encrypted = false; - - content = l_pem_load_file(filename, &label, &len); - - if (!content) - return NULL; - - return pem_load_private_key(content, len, label, passphrase, encrypted); -} diff --git a/ell/pem.h b/ell/pem.h deleted file mode 100644 index 1c93e7a..0000000 --- a/ell/pem.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2015 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_PEM_H -#define __ELL_PEM_H - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_queue; -struct l_key; -struct l_cert; -struct l_certchain; - -uint8_t *l_pem_load_buffer(const void *buf, size_t buf_len, char **type_label, - size_t *out_len); -uint8_t *l_pem_load_file(const char *filename, char **type_label, size_t *len); - -struct l_certchain *l_pem_load_certificate_chain(const char *filename); -struct l_certchain *l_pem_load_certificate_chain_from_data(const void *buf, - size_t len); -struct l_queue *l_pem_load_certificate_list(const char *filename); -struct l_queue *l_pem_load_certificate_list_from_data(const void *buf, - size_t len); - -struct l_key *l_pem_load_private_key(const char *filename, - const char *passphrase, - bool *encrypted); -struct l_key *l_pem_load_private_key_from_data(const void *buf, size_t len, - const char *passphrase, - bool *encrypted); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_PEM_H */ diff --git a/ell/pkcs5-private.h b/ell/pkcs5-private.h deleted file mode 100644 index f4f41f5..0000000 --- a/ell/pkcs5-private.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2017 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -struct l_cipher *pkcs5_cipher_from_alg_id(const uint8_t *id_asn1, - size_t id_asn1_len, - const char *password); diff --git a/ell/pkcs5.c b/ell/pkcs5.c deleted file mode 100644 index cb437e9..0000000 --- a/ell/pkcs5.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2017 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include - -#include "checksum.h" -#include "cipher.h" -#include "util.h" -#include "asn1-private.h" -#include "pkcs5.h" -#include "pkcs5-private.h" -#include "private.h" -#include "missing.h" - -/* RFC8018 section 5.1 */ -LIB_EXPORT bool l_pkcs5_pbkdf1(enum l_checksum_type type, const char *password, - const uint8_t *salt, size_t salt_len, - unsigned int iter_count, - uint8_t *out_dk, size_t dk_len) -{ - size_t hash_len, t_len; - uint8_t t[20 + salt_len + strlen(password)]; - struct l_checksum *checksum; - - switch (type) { - case L_CHECKSUM_MD5: - hash_len = 16; - break; - case L_CHECKSUM_SHA1: - hash_len = 20; - break; - case L_CHECKSUM_NONE: - case L_CHECKSUM_MD4: - case L_CHECKSUM_SHA224: - case L_CHECKSUM_SHA256: - case L_CHECKSUM_SHA384: - case L_CHECKSUM_SHA512: - return false; - default: - return false; - } - - if (dk_len > hash_len) - return false; - - checksum = l_checksum_new(type); - if (!checksum) - return false; - - memcpy(t, password, strlen(password)); - memcpy(t + strlen(password), salt, salt_len); - t_len = strlen(password) + salt_len; - - while (iter_count) { - l_checksum_reset(checksum); - - if (!l_checksum_update(checksum, t, t_len)) - break; - - if (l_checksum_get_digest(checksum, t, hash_len) != - (ssize_t) hash_len) - break; - - t_len = hash_len; - iter_count--; - } - - l_checksum_free(checksum); - - if (!iter_count) - memcpy(out_dk, t, dk_len); - - explicit_bzero(t, sizeof(t)); - return !iter_count; -} - -/* RFC8018 section 5.2 */ -LIB_EXPORT bool l_pkcs5_pbkdf2(enum l_checksum_type type, const char *password, - const uint8_t *salt, size_t salt_len, - unsigned int iter_count, - uint8_t *out_dk, size_t dk_len) -{ - size_t h_len; - struct l_checksum *checksum; - unsigned int i; - - switch (type) { - case L_CHECKSUM_SHA1: - h_len = 20; - break; - case L_CHECKSUM_SHA224: - h_len = 28; - break; - case L_CHECKSUM_SHA256: - h_len = 32; - break; - case L_CHECKSUM_SHA384: - h_len = 48; - break; - case L_CHECKSUM_SHA512: - h_len = 64; - break; - case L_CHECKSUM_NONE: - case L_CHECKSUM_MD4: - case L_CHECKSUM_MD5: - return false; - default: - return false; - } - - checksum = l_checksum_new_hmac(type, password, strlen(password)); - if (!checksum) - return false; - - for (i = 1; dk_len; i++) { - unsigned int j, k; - uint8_t u[salt_len + 64]; - size_t u_len; - size_t block_len = h_len; - - if (block_len > dk_len) - block_len = dk_len; - - memset(out_dk, 0, block_len); - - memcpy(u, salt, salt_len); - l_put_be32(i, u + salt_len); - u_len = salt_len + 4; - - for (j = 0; j < iter_count; j++) { - l_checksum_reset(checksum); - - if (!l_checksum_update(checksum, u, u_len)) - break; - - if (l_checksum_get_digest(checksum, u, h_len) != - (ssize_t) h_len) - break; - - u_len = h_len; - - for (k = 0; k < block_len; k++) - out_dk[k] ^= u[k]; - } - - if (j < iter_count) - break; - - out_dk += block_len; - dk_len -= block_len; - } - - l_checksum_free(checksum); - - return !dk_len; -} - -static struct asn1_oid pkcs5_pbkdf2_oid = { - 9, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c } -}; - -static struct asn1_oid pkcs5_pbes2_oid = { - 9, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0d } -}; - -static const struct pkcs5_pbes1_encryption_oid { - enum l_checksum_type checksum_type; - enum l_cipher_type cipher_type; - struct asn1_oid oid; -} pkcs5_pbes1_encryption_oids[] = { - { /* pbeWithMD5AndDES-CBC */ - L_CHECKSUM_MD5, L_CIPHER_DES_CBC, - { 9, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x03 } }, - }, - { /* pbeWithSHA1AndDES-CBC */ - L_CHECKSUM_SHA1, L_CIPHER_DES_CBC, - { 9, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0a } }, - }, - /* MD2- and RC2-based schemes 1, 4, 6 and 11 not supported */ -}; - -static const struct pkcs5_digest_alg_oid { - enum l_checksum_type type; - struct asn1_oid oid; -} pkcs5_digest_alg_oids[] = { - { /* hmacWithSHA1 */ - L_CHECKSUM_SHA1, - { 8, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x07 } }, - }, - { /* hmacWithSHA224 */ - L_CHECKSUM_SHA224, - { 8, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x08 } }, - }, - { /* hmacWithSHA256 */ - L_CHECKSUM_SHA256, - { 8, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x09 } }, - }, - { /* hmacWithSHA384 */ - L_CHECKSUM_SHA384, - { 8, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x0a } }, - }, - { /* hmacWithSHA512 */ - L_CHECKSUM_SHA512, - { 8, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x0b } }, - }, - /* hmacWithSHA512-224 and hmacWithSHA512-256 not supported */ -}; - -static const struct pkcs5_enc_alg_oid { - enum l_cipher_type cipher_type; - uint8_t key_size, iv_size; - struct asn1_oid oid; -} pkcs5_enc_alg_oids[] = { - { /* desCBC */ - L_CIPHER_DES_CBC, 8, 8, - { 5, { 0x2b, 0x0e, 0x03, 0x02, 0x07 } }, - }, - { /* des-EDE3-CBC */ - L_CIPHER_DES3_EDE_CBC, 24, 8, - { 8, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x07 } }, - }, - /* RC2/RC5-based schemes 2 and 9 not supported */ - { /* aes128-CBC-PAD */ - L_CIPHER_AES_CBC, 16, 16, - { 9, { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02 } }, - }, - { /* aes192-CBC-PAD */ - L_CIPHER_AES_CBC, 24, 16, - { 9, { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x16 } }, - }, - { /* aes256-CBC-PAD */ - L_CIPHER_AES_CBC, 32, 16, - { 9, { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2a } }, - }, -}; - -static struct l_cipher *pkcs5_cipher_from_pbes2_params( - const uint8_t *pbes2_params, - size_t pbes2_params_len, - const char *password) -{ - uint8_t tag; - const uint8_t *kdf_sequence, *enc_sequence, *oid, *params, - *salt, *iter_count_buf, *key_len_buf, *prf_sequence; - size_t kdf_len, enc_len, params_len, salt_len, key_len, tmp_len; - unsigned int i, iter_count, pos; - enum l_checksum_type prf_alg = L_CHECKSUM_NONE; - const struct pkcs5_enc_alg_oid *enc_scheme = NULL; - uint8_t derived_key[64]; - struct l_cipher *cipher; - - /* RFC8018 section A.4 */ - - kdf_sequence = asn1_der_find_elem(pbes2_params, pbes2_params_len, 0, - &tag, &kdf_len); - if (!kdf_sequence || tag != ASN1_ID_SEQUENCE) - return NULL; - - enc_sequence = asn1_der_find_elem(pbes2_params, pbes2_params_len, 1, - &tag, &enc_len); - if (!enc_sequence || tag != ASN1_ID_SEQUENCE) - return NULL; - - if (asn1_der_find_elem(pbes2_params, pbes2_params_len, 2, - &tag, &tmp_len)) - return NULL; - - /* RFC8018 section A.2 */ - - oid = asn1_der_find_elem(kdf_sequence, kdf_len, 0, &tag, &tmp_len); - if (!oid || tag != ASN1_ID_OID) - return NULL; - - if (!asn1_oid_eq(&pkcs5_pbkdf2_oid, tmp_len, oid)) - return NULL; - - params = asn1_der_find_elem(kdf_sequence, kdf_len, 1, - &tag, ¶ms_len); - if (!params || tag != ASN1_ID_SEQUENCE) - return NULL; - - if (asn1_der_find_elem(kdf_sequence, kdf_len, 2, &tag, &tmp_len)) - return NULL; - - salt = asn1_der_find_elem(params, params_len, 0, &tag, &salt_len); - if (!salt || tag != ASN1_ID_OCTET_STRING || - salt_len < 1 || salt_len > 512) - return NULL; - - iter_count_buf = asn1_der_find_elem(params, params_len, 1, - &tag, &tmp_len); - if (!iter_count_buf || tag != ASN1_ID_INTEGER || - tmp_len < 1 || tmp_len > 4) - return NULL; - - iter_count = 0; - - while (tmp_len--) - iter_count = (iter_count << 8) | *iter_count_buf++; - - pos = 2; - key_len_buf = asn1_der_find_elem(params, params_len, pos, - &tag, &tmp_len); - if (key_len_buf && tag == ASN1_ID_INTEGER) { - if (tmp_len != 1) - return NULL; - - pos++; - key_len = 0; - - while (tmp_len--) - key_len = (key_len << 8) | *key_len_buf++; - } else - key_len = 0; - - prf_sequence = asn1_der_find_elem(params, params_len, pos, - &tag, &tmp_len); - if (prf_sequence && tag == ASN1_ID_SEQUENCE) { - pos++; - - oid = asn1_der_find_elem(prf_sequence, tmp_len, 0, - &tag, &tmp_len); - if (!oid || tag != ASN1_ID_OID) - return NULL; - - for (i = 0; i < L_ARRAY_SIZE(pkcs5_digest_alg_oids); i++) - if (asn1_oid_eq(&pkcs5_digest_alg_oids[i].oid, - tmp_len, oid)) - prf_alg = pkcs5_digest_alg_oids[i].type; - - if (prf_alg == L_CHECKSUM_NONE) - return NULL; - } else - prf_alg = L_CHECKSUM_SHA1; - - oid = asn1_der_find_elem(enc_sequence, enc_len, 0, &tag, &tmp_len); - if (!oid || tag != ASN1_ID_OID) - return NULL; - - for (i = 0; i < L_ARRAY_SIZE(pkcs5_enc_alg_oids); i++) { - if (asn1_oid_eq(&pkcs5_enc_alg_oids[i].oid, tmp_len, oid)) { - enc_scheme = &pkcs5_enc_alg_oids[i]; - break; - } - } - - if (!enc_scheme) - return NULL; - - params = asn1_der_find_elem(enc_sequence, enc_len, 1, - &tag, ¶ms_len); - if (!params) - return NULL; - - /* RFC8018 section B.2 */ - - /* - * Since we don't support RC2/RC5, all our PKCS#5 ciphers only - * have an obligatory OCTET STRING IV parameter and a fixed key - * length. - */ - if (tag != ASN1_ID_OCTET_STRING || params_len != enc_scheme->iv_size) - return NULL; - - if (key_len && enc_scheme->key_size != key_len) - return NULL; - - key_len = enc_scheme->key_size; - - if (asn1_der_find_elem(enc_sequence, enc_len, 2, &tag, &tmp_len)) - return NULL; - - /* RFC8018 section 6.2 */ - - if (!l_pkcs5_pbkdf2(prf_alg, password, salt, salt_len, iter_count, - derived_key, key_len)) - return NULL; - - cipher = l_cipher_new(enc_scheme->cipher_type, derived_key, key_len); - if (cipher && !l_cipher_set_iv(cipher, params, enc_scheme->iv_size)) { - l_cipher_free(cipher); - cipher = NULL; - } - - explicit_bzero(derived_key, 16); - return cipher; -} - -struct l_cipher *pkcs5_cipher_from_alg_id(const uint8_t *id_asn1, - size_t id_asn1_len, - const char *password) -{ - uint8_t tag; - const uint8_t *oid, *params, *salt, *iter_count_buf; - size_t oid_len, params_len, tmp_len; - unsigned int i, iter_count; - const struct pkcs5_pbes1_encryption_oid *pbes1_scheme = NULL; - uint8_t derived_key[16]; - struct l_cipher *cipher; - - oid = asn1_der_find_elem(id_asn1, id_asn1_len, 0, &tag, &oid_len); - if (!oid || tag != ASN1_ID_OID) - return NULL; - - params = asn1_der_find_elem(id_asn1, id_asn1_len, 1, &tag, ¶ms_len); - if (!params || tag != ASN1_ID_SEQUENCE) - return NULL; - - if (asn1_der_find_elem(id_asn1, id_asn1_len, 2, &tag, &tmp_len)) - return NULL; - - if (asn1_oid_eq(&pkcs5_pbes2_oid, oid_len, oid)) - return pkcs5_cipher_from_pbes2_params(params, params_len, - password); - - /* RFC8018 section A.3 */ - - for (i = 0; i < L_ARRAY_SIZE(pkcs5_pbes1_encryption_oids); i++) { - if (asn1_oid_eq(&pkcs5_pbes1_encryption_oids[i].oid, - oid_len, oid)) { - pbes1_scheme = &pkcs5_pbes1_encryption_oids[i]; - break; - } - } - - if (!pbes1_scheme) - return NULL; - - salt = asn1_der_find_elem(params, params_len, 0, &tag, &tmp_len); - if (!salt || tag != ASN1_ID_OCTET_STRING || tmp_len != 8) - return NULL; - - iter_count_buf = asn1_der_find_elem(params, params_len, 1, - &tag, &tmp_len); - if (!iter_count_buf || tag != ASN1_ID_INTEGER || - tmp_len < 1 || tmp_len > 4) - return NULL; - - iter_count = 0; - - while (tmp_len--) - iter_count = (iter_count << 8) | *iter_count_buf++; - - if (asn1_der_find_elem(params, params_len, 2, &tag, &tmp_len)) - return NULL; - - /* RFC8018 section 6.1 */ - - if (!l_pkcs5_pbkdf1(pbes1_scheme->checksum_type, - password, salt, 8, iter_count, derived_key, 16)) - return NULL; - - cipher = l_cipher_new(pbes1_scheme->cipher_type, derived_key + 0, 8); - if (cipher && !l_cipher_set_iv(cipher, derived_key + 8, 8)) { - l_cipher_free(cipher); - cipher = NULL; - } - - explicit_bzero(derived_key, 16); - return cipher; -} diff --git a/ell/pkcs5.h b/ell/pkcs5.h deleted file mode 100644 index ff7bdfd..0000000 --- a/ell/pkcs5.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2017 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_PKCS5_H -#define __ELL_PKCS5_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -bool l_pkcs5_pbkdf1(enum l_checksum_type type, const char *password, - const uint8_t *salt, size_t salt_len, - unsigned int iter_count, - uint8_t *out_dk, size_t dk_len); - -bool l_pkcs5_pbkdf2(enum l_checksum_type type, const char *password, - const uint8_t *salt, size_t salt_len, - unsigned int iter_count, - uint8_t *out_dk, size_t dk_len); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_PKCS5_H */ diff --git a/ell/plugin.c b/ell/plugin.c deleted file mode 100644 index 21b81d0..0000000 --- a/ell/plugin.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include -#include -#include -#include - -#include "util.h" -#include "queue.h" -#include "plugin.h" -#include "log.h" -#include "private.h" - -/** - * SECTION:plugin - * @short_description: Plugin framework - * - * Plugin framework - */ - -/** - * l_plugin_desc: - * - * Plugin descriptor. - */ - -static struct l_queue *plugin_list; - -struct plugin { - void *handle; - bool active; - const struct l_plugin_desc *desc; -}; - -static void plugin_destroy(void *user_data) -{ - struct plugin *plugin = user_data; - - if (plugin->active && plugin->desc->exit) - plugin->desc->exit(); - - if (plugin->handle) - dlclose(plugin->handle); - - l_free(plugin); -} - -static int compare_priority(const void *a, const void *b, void *user_data) -{ - const struct plugin *plugin_a = a; - const struct plugin *plugin_b = b; - - return plugin_a->desc->priority - plugin_b->desc->priority; -} - -static bool plugin_add(void *handle, const struct l_plugin_desc *desc, - const char *version) -{ - struct plugin *plugin; - - if (!desc->init) - return false; - - if (version) { - if (!desc->version) - return false; - - if (strcmp(desc->version, version)) - return false; - } - - plugin = l_new(struct plugin, 1); - - plugin->handle = handle; - plugin->active = false; - plugin->desc = desc; - - l_queue_insert(plugin_list, plugin, compare_priority, NULL); - - if (desc->debug_start && desc->debug_stop) - debug_enable(desc->debug_start, desc->debug_stop); - - return true; -} - -static void plugin_start(void *data, void *user_data) -{ - struct plugin *plugin = data; - - if (plugin->desc->init() < 0) - return; - - plugin->active = true; -} - -static void update_debug(void *data, void *user_data) -{ - struct plugin *plugin = data; - - if (plugin->desc->debug_start && plugin->desc->debug_stop) - debug_enable(plugin->desc->debug_start, - plugin->desc->debug_stop); -} - -void plugin_update_debug(void) -{ - l_queue_foreach(plugin_list, update_debug, NULL); -} - -/** - * l_plugin_add: - * @desc: plugin description record - * @version: version string or #NULL - * - * Adds plugin description. - **/ -LIB_EXPORT void l_plugin_add(const struct l_plugin_desc *desc, - const char *version) -{ - if (!plugin_list) - plugin_list = l_queue_new(); - - if (!desc) - return; - - plugin_add(NULL, desc, version); -} - -/** - * l_plugin_load: - * @pattern: file pattern - * @symbol: plugin descriptor symbol - * @version: version string or #NULL - * - * Loads plugins from @pattern location and execute @symbol plugin descriptor. - **/ -LIB_EXPORT void l_plugin_load(const char *pattern, const char *symbol, - const char *version) -{ - glob_t gl; - size_t i; - - if (!plugin_list) - plugin_list = l_queue_new(); - - if (!pattern || !symbol) - goto done; - - if (glob(pattern, GLOB_NOSORT, NULL, &gl)) - goto done; - - for (i = 0; i < gl.gl_pathc; i++) { - void *handle; - struct l_plugin_desc *desc; - - handle = dlopen(gl.gl_pathv[i], RTLD_NOW); - if (!handle) { - l_info("Unable to load %s: %s", - gl.gl_pathv[i], dlerror()); - continue; - } - - desc = dlsym(handle, symbol); - if (!desc) { - dlclose(handle); - continue; - } - - if (!plugin_add(handle, desc, version)) - dlclose(handle); - } - - globfree(&gl); - -done: - l_queue_foreach(plugin_list, plugin_start, NULL); -} - -/** - * l_plugin_unload: - * - * Unload all plugins. - **/ -LIB_EXPORT void l_plugin_unload(void) -{ - if (!plugin_list) - return; - - l_queue_reverse(plugin_list); - - l_queue_destroy(plugin_list, plugin_destroy); - - plugin_list = NULL; -} diff --git a/ell/plugin.h b/ell/plugin.h deleted file mode 100644 index 5ca95dc..0000000 --- a/ell/plugin.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_PLUGIN_H -#define __ELL_PLUGIN_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define L_PLUGIN_PRIORITY_LOW -100 -#define L_PLUGIN_PRIORITY_DEFAULT 0 -#define L_PLUGIN_PRIORITY_HIGH 100 - -struct l_plugin_desc { - const char *name; - const char *description; - const char *version; - int priority; - int (*init) (void); - void (*exit) (void); - void *debug_start; - void *debug_stop; -}; - - -#define L_PLUGIN_DEFINE(symbol, name, description, version, \ - priority, init, exit) \ - extern struct l_plugin_desc symbol \ - __attribute__ ((visibility("default"))); \ - struct l_plugin_desc symbol = { \ - #name, description, version, priority, init, exit, \ - NULL, NULL \ - }; - -#define L_PLUGIN_DEFINE_DEBUG(symbol, name, description, version, \ - priority, init, exit, debug) \ - extern struct l_debug_desc __start_ ##debug[] \ - __attribute__ ((weak, visibility("hidden"))); \ - extern struct l_debug_desc __stop_ ##debug[] \ - __attribute__ ((weak, visibility("hidden"))); \ - extern struct l_plugin_desc symbol \ - __attribute__ ((visibility("default"))); \ - struct l_plugin_desc symbol = { \ - #name, description, version, priority, init, exit, \ - __start_ ##debug, __stop_ ##debug \ - }; - -void l_plugin_add(const struct l_plugin_desc *desc, const char *version); - -void l_plugin_load(const char *pattern, const char *symbol, - const char *version); -void l_plugin_unload(void); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_PLUGIN_H */ diff --git a/ell/private.h b/ell/private.h deleted file mode 100644 index 4dc48d7..0000000 --- a/ell/private.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include - -#include - -#define uninitialized_var(x) x = x - -#define align_len(len, boundary) (((len)+(boundary)-1) & ~((boundary)-1)) - -#define LIB_EXPORT __attribute__ ((visibility("default"))) - -struct l_debug_desc; - -void debug_enable(struct l_debug_desc *start, struct l_debug_desc *stop); -void debug_disable(struct l_debug_desc *start, struct l_debug_desc *stop); - -void plugin_update_debug(void); - -typedef void (*watch_event_cb_t) (int fd, uint32_t events, void *user_data); -typedef void (*watch_destroy_cb_t) (void *user_data); - -typedef void (*idle_event_cb_t) (void *user_data); -typedef void (*idle_destroy_cb_t) (void *user_data); - -int watch_add(int fd, uint32_t events, watch_event_cb_t callback, - void *user_data, watch_destroy_cb_t destroy); -int watch_modify(int fd, uint32_t events, bool force); -int watch_remove(int fd); -int watch_clear(int fd); - -#define IDLE_FLAG_NO_WARN_DANGLING 0x10000000 -int idle_add(idle_event_cb_t callback, void *user_data, uint32_t flags, - idle_destroy_cb_t destroy); -void idle_remove(int id); diff --git a/ell/queue.c b/ell/queue.c deleted file mode 100644 index 0f6ed3e..0000000 --- a/ell/queue.c +++ /dev/null @@ -1,589 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "util.h" -#include "queue.h" -#include "private.h" - -/** - * SECTION:queue - * @short_description: Queue support - * - * Queue support - */ - -/** - * l_queue: - * - * Opague object representing the queue. - */ -struct l_queue { - struct l_queue_entry *head; - struct l_queue_entry *tail; - unsigned int entries; -}; - -/** - * l_queue_new: - * - * Create a new queue. - * - * No error handling is needed since. In case of real memory allocation - * problems abort() will be called. - * - * Returns: a newly allocated #l_queue object - **/ -LIB_EXPORT struct l_queue *l_queue_new(void) -{ - struct l_queue *queue; - - queue = l_new(struct l_queue, 1); - - queue->head = NULL; - queue->tail = NULL; - queue->entries = 0; - - return queue; -} - -/** - * l_queue_destroy: - * @queue: queue object - * @destroy: destroy function - * - * Free queue and call @destory on all remaining entries. - **/ -LIB_EXPORT void l_queue_destroy(struct l_queue *queue, - l_queue_destroy_func_t destroy) -{ - l_queue_clear(queue, destroy); - l_free(queue); -} - -/** - * l_queue_clear: - * @queue: queue object - * @destroy: destroy function - * - * Clear queue and call @destory on all remaining entries. - **/ -LIB_EXPORT void l_queue_clear(struct l_queue *queue, - l_queue_destroy_func_t destroy) -{ - struct l_queue_entry *entry; - - if (unlikely(!queue)) - return; - - entry = queue->head; - - while (entry) { - struct l_queue_entry *tmp = entry; - - if (destroy) - destroy(entry->data); - - entry = entry->next; - - l_free(tmp); - } - - queue->head = NULL; - queue->tail = NULL; - queue->entries = 0; -} - -/** - * l_queue_push_tail: - * @queue: queue object - * @data: pointer to data - * - * Adds @data pointer at the end of the queue. - * - * Returns: #true when data has been added and #false in case an invalid - * @queue object has been provided - **/ -LIB_EXPORT bool l_queue_push_tail(struct l_queue *queue, void *data) -{ - struct l_queue_entry *entry; - - if (unlikely(!queue)) - return false; - - entry = l_new(struct l_queue_entry, 1); - - entry->data = data; - entry->next = NULL; - - if (queue->tail) - queue->tail->next = entry; - - queue->tail = entry; - - if (!queue->head) - queue->head = entry; - - queue->entries++; - - return true; -} - -/** - * l_queue_push_head: - * @queue: queue object - * @data: pointer to data - * - * Adds @data pointer at the start of the queue. - * - * Returns: #true when data has been added and #false in case an invalid - * @queue object has been provided - **/ -LIB_EXPORT bool l_queue_push_head(struct l_queue *queue, void *data) -{ - struct l_queue_entry *entry; - - if (unlikely(!queue)) - return false; - - entry = l_new(struct l_queue_entry, 1); - - entry->data = data; - entry->next = queue->head; - - queue->head = entry; - - if (!queue->tail) - queue->tail = entry; - - queue->entries++; - - return true; -} - -/** - * l_queue_pop_head: - * @queue: queue object - * - * Removes the first element of the queue an returns it. - * - * Returns: data pointer to first element or #NULL in case an empty queue - **/ -LIB_EXPORT void *l_queue_pop_head(struct l_queue *queue) -{ - struct l_queue_entry *entry; - void *data; - - if (unlikely(!queue)) - return NULL; - - if (!queue->head) - return NULL; - - entry = queue->head; - - if (!queue->head->next) { - queue->head = NULL; - queue->tail = NULL; - } else - queue->head = queue->head->next; - - data = entry->data; - - l_free(entry); - - queue->entries--; - - return data; -} - -/** - * l_queue_peek_head: - * @queue: queue object - * - * Peeks at the first element of the queue an returns it. - * - * Returns: data pointer to first element or #NULL in case an empty queue - **/ -LIB_EXPORT void *l_queue_peek_head(struct l_queue *queue) -{ - struct l_queue_entry *entry; - - if (unlikely(!queue)) - return NULL; - - if (!queue->head) - return NULL; - - entry = queue->head; - return entry->data; -} - -/** - * l_queue_peek_tail: - * @queue: queue object - * - * Peeks at the last element of the queue an returns it. - * - * Returns: data pointer to first element or #NULL in case an empty queue - **/ -LIB_EXPORT void *l_queue_peek_tail(struct l_queue *queue) -{ - struct l_queue_entry *entry; - - if (unlikely(!queue)) - return NULL; - - if (!queue->tail) - return NULL; - - entry = queue->tail; - return entry->data; -} - -/** - * l_queue_insert: - * @queue: queue object - * @data: pointer to data - * @function: compare function - * @user_data: user data given to compare function - * - * Inserts @data pointer at a position in the queue determined by the - * compare @function. @function should return > 0 if the @data (first - * parameter) should be inserted after the current entry (second parameter). - * - * Returns: #true when data has been added and #false in case of failure - **/ -LIB_EXPORT bool l_queue_insert(struct l_queue *queue, void *data, - l_queue_compare_func_t function, void *user_data) -{ - struct l_queue_entry *entry, *prev, *cur; - int cmp; - - if (unlikely(!queue || !function)) - return false; - - entry = l_new(struct l_queue_entry, 1); - - entry->data = data; - entry->next = NULL; - - if (!queue->head) { - queue->head = entry; - queue->tail = entry; - goto done; - } - - for (prev = NULL, cur = queue->head; cur; prev = cur, cur = cur->next) { - cmp = function(entry->data, cur->data, user_data); - - if (cmp >= 0) - continue; - - if (prev == NULL) { - entry->next = queue->head; - queue->head = entry; - goto done; - } - - entry->next = cur; - prev->next = entry; - - goto done; - } - - queue->tail->next = entry; - queue->tail = entry; - -done: - queue->entries++; - - return true; -} - -/** - * l_queue_find: - * @queue: queue object - * @function: match function - * @user_data: user data given to compare function - * - * Finds an entry in the queue by running the match @function - * - * Returns: Matching entry or NULL if no entry can be found - **/ -LIB_EXPORT void *l_queue_find(struct l_queue *queue, - l_queue_match_func_t function, - const void *user_data) -{ - struct l_queue_entry *entry; - - if (unlikely(!queue || !function)) - return NULL; - - for (entry = queue->head; entry; entry = entry->next) - if (function(entry->data, user_data)) - return entry->data; - - return NULL; -} - -/** - * l_queue_remove: - * @queue: queue object - * @data: pointer to data - * - * Remove given @data from the queue. - * - * Returns: #true when data has been removed and #false when data could not - * be found or an invalid @queue object has been provided - **/ -LIB_EXPORT bool l_queue_remove(struct l_queue *queue, void *data) -{ - struct l_queue_entry *entry, *prev; - - if (unlikely(!queue)) - return false; - - for (entry = queue->head, prev = NULL; entry; - prev = entry, entry = entry->next) { - if (entry->data != data) - continue; - - if (prev) - prev->next = entry->next; - else - queue->head = entry->next; - - if (!entry->next) - queue->tail = prev; - - l_free(entry); - - queue->entries--; - - return true; - } - - return false; -} - -/** - * l_queue_reverse: - * @queue: queue object - * - * Reverse entries in the queue. - * - * Returns: #true on success and #false on failure - **/ -LIB_EXPORT bool l_queue_reverse(struct l_queue *queue) -{ - struct l_queue_entry *entry, *prev = NULL; - - if (unlikely(!queue)) - return false; - - entry = queue->head; - - while (entry) { - struct l_queue_entry *next = entry->next; - - entry->next = prev; - - prev = entry; - entry = next; - } - - queue->tail = queue->head; - queue->head = prev; - - return true; -} - -/** - * l_queue_foreach: - * @queue: queue object - * @function: callback function - * @user_data: user data given to callback function - * - * Call @function for every given data in @queue. - **/ -LIB_EXPORT void l_queue_foreach(struct l_queue *queue, - l_queue_foreach_func_t function, void *user_data) -{ - struct l_queue_entry *entry; - - if (unlikely(!queue || !function)) - return; - - for (entry = queue->head; entry; entry = entry->next) - function(entry->data, user_data); -} - -/** - * l_queue_foreach_remove: - * @queue: queue object - * @function: callback function - * @user_data: user data given to callback function - * - * Remove all entries in the @queue where @function returns #true. - * - * Returns: number of removed entries - **/ -LIB_EXPORT unsigned int l_queue_foreach_remove(struct l_queue *queue, - l_queue_remove_func_t function, void *user_data) -{ - struct l_queue_entry *entry, *prev = NULL; - unsigned int count = 0; - - if (unlikely(!queue || !function)) - return 0; - - entry = queue->head; - - while (entry) { - if (function(entry->data, user_data)) { - struct l_queue_entry *tmp = entry; - - if (prev) - prev->next = entry->next; - else - queue->head = entry->next; - - if (!entry->next) - queue->tail = prev; - - entry = entry->next; - - l_free(tmp); - - count++; - } else { - prev = entry; - entry = entry->next; - } - } - - queue->entries -= count; - - return count; -} - -/** - * l_queue_remove_if - * @queue: queue object - * @function: callback function - * @user_data: user data given to callback function - * - * Remove the first entry in the @queue where the function returns #true. - * - * Returns: NULL if no entry was found, or the entry data if removal was - * successful. - **/ -LIB_EXPORT void *l_queue_remove_if(struct l_queue *queue, - l_queue_match_func_t function, - const void *user_data) -{ - struct l_queue_entry *entry, *prev = NULL; - - if (unlikely(!queue || !function)) - return NULL; - - entry = queue->head; - - while (entry) { - if (function(entry->data, user_data)) { - struct l_queue_entry *tmp = entry; - void *data; - - if (prev) - prev->next = entry->next; - else - queue->head = entry->next; - - if (!entry->next) - queue->tail = prev; - - entry = entry->next; - - data = tmp->data; - - l_free(tmp); - queue->entries--; - - return data; - } else { - prev = entry; - entry = entry->next; - } - } - - return NULL; -} - -/** - * l_queue_length: - * @queue: queue object - * - * Returns: entries of the queue - **/ -LIB_EXPORT unsigned int l_queue_length(struct l_queue *queue) -{ - if (unlikely(!queue)) - return 0; - - return queue->entries; -} - -/** - * l_queue_isempty: - * @queue: queue object - * - * Returns: #true if @queue is empty and #false is not - **/ -LIB_EXPORT bool l_queue_isempty(struct l_queue *queue) -{ - if (unlikely(!queue)) - return true; - - return queue->entries == 0; -} - -/** - * l_queue_get_entries: - * @queue: queue object - * - * This function gives direct, read-only access to the internal list structure - * of the queue. This can be used to efficiently traverse the elements. - * - * Returns: A pointer to the head of the queue. - **/ -LIB_EXPORT const struct l_queue_entry *l_queue_get_entries( - struct l_queue *queue) -{ - if (unlikely(!queue)) - return NULL; - - return queue->head; -} diff --git a/ell/queue.h b/ell/queue.h deleted file mode 100644 index ff46a08..0000000 --- a/ell/queue.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_QUEUE_H -#define __ELL_QUEUE_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*l_queue_foreach_func_t) (void *data, void *user_data); -typedef void (*l_queue_destroy_func_t) (void *data); -typedef int (*l_queue_compare_func_t) (const void *a, const void *b, - void *user_data); -typedef bool (*l_queue_match_func_t) (const void *a, const void *b); -typedef bool (*l_queue_remove_func_t) (void *data, void *user_data); - -struct l_queue; - -struct l_queue_entry { - void *data; - struct l_queue_entry *next; -}; - -struct l_queue *l_queue_new(void); -void l_queue_destroy(struct l_queue *queue, - l_queue_destroy_func_t destroy); -void l_queue_clear(struct l_queue *queue, - l_queue_destroy_func_t destroy); - -bool l_queue_push_tail(struct l_queue *queue, void *data); -bool l_queue_push_head(struct l_queue *queue, void *data); -void *l_queue_pop_head(struct l_queue *queue); -void *l_queue_peek_head(struct l_queue *queue); -void *l_queue_peek_tail(struct l_queue *queue); - -bool l_queue_insert(struct l_queue *queue, void *data, - l_queue_compare_func_t function, void *user_data); -void *l_queue_find(struct l_queue *queue, - l_queue_match_func_t function, const void *user_data); -bool l_queue_remove(struct l_queue *queue, void *data); -void *l_queue_remove_if(struct l_queue *queue, - l_queue_match_func_t function, const void *user_data); - -bool l_queue_reverse(struct l_queue *queue); - -void l_queue_foreach(struct l_queue *queue, - l_queue_foreach_func_t function, void *user_data); -unsigned int l_queue_foreach_remove(struct l_queue *queue, - l_queue_remove_func_t function, void *user_data); - -unsigned int l_queue_length(struct l_queue *queue); -bool l_queue_isempty(struct l_queue *queue); - -const struct l_queue_entry *l_queue_get_entries(struct l_queue *queue); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_QUEUE_H */ diff --git a/ell/random.c b/ell/random.c deleted file mode 100644 index 3390318..0000000 --- a/ell/random.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2015 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include - -#include "random.h" -#include "private.h" -#include "missing.h" - -#ifndef GRND_NONBLOCK -#define GRND_NONBLOCK 0x0001 -#endif - -#ifndef GRND_RANDOM -#define GRND_RANDOM 0x0002 -#endif - -static inline int getrandom(void *buffer, size_t count, unsigned flags) { - return syscall(__NR_getrandom, buffer, count, flags); -} - -/** - * l_getrandom: - * @buf: buffer to fill with random data - * @len: length of random data requested - * - * Request a number of randomly generated bytes given by @len and put them - * into buffer @buf. - * - * Returns: true if the random data could be generated, false otherwise. - **/ -LIB_EXPORT bool l_getrandom(void *buf, size_t len) -{ - while (len) { - int ret; - - ret = L_TFR(getrandom(buf, len, 0)); - if (ret < 0) - return false; - - buf += ret; - len -= ret; - } - - return true; -} - -LIB_EXPORT bool l_getrandom_is_supported() -{ - static bool initialized = false; - static bool supported = true; - uint8_t buf[4]; - int ret; - - if (initialized) - return supported; - - ret = getrandom(buf, sizeof(buf), GRND_NONBLOCK); - - if (ret < 0 && errno == ENOSYS) - supported = false; - - initialized = true; - return supported; -} - -LIB_EXPORT uint32_t l_getrandom_uint32(void) -{ - int ret; - uint32_t u; - - ret = getrandom(&u, sizeof(u), GRND_NONBLOCK); - - if (ret == sizeof(u)) - return u; - - return random() * RAND_MAX + random(); -} diff --git a/ell/random.h b/ell/random.h deleted file mode 100644 index 49a4637..0000000 --- a/ell/random.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2015 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_RANDOM_H -#define __ELL_RANDOM_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -bool l_getrandom(void *buf, size_t len); -bool l_getrandom_is_supported(); - -uint32_t l_getrandom_uint32(void); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_RANDOM_H */ diff --git a/ell/ringbuf.c b/ell/ringbuf.c deleted file mode 100644 index 49f370c..0000000 --- a/ell/ringbuf.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2015 Intel Corporation. All rights reserved. - * - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include -#include -#include -#include - -#include "private.h" -#include "ringbuf.h" - -/** - * SECTION:ringbuf - * @short_description: Ring Buffer support - * - * Ring Buffer support - */ - -/** - * l_ringbuf: - * - * Opague object representing the Ring Buffer. - */ -struct l_ringbuf { - void *buffer; - size_t size; - size_t in; - size_t out; - l_ringbuf_tracing_func_t in_tracing; - void *in_data; -}; - -#define RINGBUF_RESET 0 - -/* Find last (most siginificant) set bit */ -static inline unsigned int fls(unsigned int x) -{ - return x ? sizeof(x) * 8 - __builtin_clz(x) : 0; -} - -/* Round up to nearest power of two */ -static inline unsigned int align_power2(unsigned int u) -{ - return 1 << fls(u - 1); -} - -/** - * l_ringbuf_new: - * @size: Minimum size of the ring buffer. - * - * Create a new ring buffer - * - * Returns: a newly allocated #l_ringbuf object - **/ -LIB_EXPORT struct l_ringbuf *l_ringbuf_new(size_t size) -{ - struct l_ringbuf *ringbuf; - size_t real_size; - - if (size < 2 || size > UINT_MAX) - return NULL; - - /* Find the next power of two for size */ - real_size = align_power2(size); - - ringbuf = l_new(struct l_ringbuf, 1); - ringbuf->buffer = l_malloc(real_size); - - ringbuf->size = real_size; - ringbuf->in = RINGBUF_RESET; - ringbuf->out = RINGBUF_RESET; - - return ringbuf; -} - -/** - * l_ringbuf_free: - * @ringbuf: Ring Buffer object - * - * Free the Ring Buffer object and associated memory. - **/ -LIB_EXPORT void l_ringbuf_free(struct l_ringbuf *ringbuf) -{ - if (!ringbuf) - return; - - l_free(ringbuf->buffer); - l_free(ringbuf); -} - -/** - * l_ringbuf_set_input_tracing: - * @ringbuf: Ring Buffer object - * @callback: Callback function - * @user_data: user_data for the callback function - * - * Sets a tracing callback that will be called whenever input data is - * processed. @user_data will be passed to the callback. - * - * Returns: Whether setting the callback succeeded. - **/ -LIB_EXPORT bool l_ringbuf_set_input_tracing(struct l_ringbuf *ringbuf, - l_ringbuf_tracing_func_t callback, void *user_data) -{ - if (!ringbuf) - return false; - - ringbuf->in_tracing = callback; - ringbuf->in_data = user_data; - - return true; -} - -/** - * l_ringbuf_capacity: - * @ringbuf: Ring Buffer object - * - * Returns: Total capacity of the Ring Buffer. - **/ -LIB_EXPORT size_t l_ringbuf_capacity(struct l_ringbuf *ringbuf) -{ - if (!ringbuf) - return 0; - - return ringbuf->size; -} - -/** - * l_ringbuf_len: - * @ringbuf: Ring Buffer object - * - * Returns: Number of occupied bytes in the ring buffer - **/ -LIB_EXPORT size_t l_ringbuf_len(struct l_ringbuf *ringbuf) -{ - if (!ringbuf) - return 0; - - return ringbuf->in - ringbuf->out; -} - -/** - * l_ringbuf_drain: - * @ringbuf: Ring Buffer object - * @count: Number of bytes to drain - * - * Drains a number of bytes specified. The occupied bytes are discarded. - * - * Returns: Number of bytes drained - **/ -LIB_EXPORT size_t l_ringbuf_drain(struct l_ringbuf *ringbuf, size_t count) -{ - size_t len; - - if (!ringbuf) - return 0; - - len = minsize(count, ringbuf->in - ringbuf->out); - if (!len) - return 0; - - ringbuf->out += len; - - if (ringbuf->out == ringbuf->in) { - ringbuf->in = RINGBUF_RESET; - ringbuf->out = RINGBUF_RESET; - } - - return len; -} - -/** - * l_ringbuf_peek: - * @ringbuf: Ring Buffer object - * @offset: Offset into the ring buffer - * @len_nowrap: Number of contiguous bytes starting from the current offset - * - * Peeks into the ring buffer at offset specified by @offset. Since the ring - * buffer can wrap around, the stored bytes might be in two contiguous - * locations. Typically offset of 0 is used first. Then, if len_nowrap - * is less than the length returned by l_ringbuf_len, the rest of the data - * can be obtained by calling l_ringbuf_peek with offset set to len_nowrap. - * - * Returns: Pointer into ring buffer internal storage - **/ -LIB_EXPORT void *l_ringbuf_peek(struct l_ringbuf *ringbuf, size_t offset, - size_t *len_nowrap) -{ - if (!ringbuf) - return NULL; - - offset = (ringbuf->out + offset) & (ringbuf->size - 1); - - if (len_nowrap) { - size_t len = ringbuf->in - ringbuf->out; - *len_nowrap = minsize(len, ringbuf->size - offset); - } - - return ringbuf->buffer + offset; -} - -/** - * l_ringbuf_write: - * @ringbuf: Ring Buffer object - * @fd: file descriptor to write to - * - * Tries to write the contents of the ring buffer out to a file descriptor - * - * Returns: Number of bytes written or -1 if the write failed. - **/ -LIB_EXPORT ssize_t l_ringbuf_write(struct l_ringbuf *ringbuf, int fd) -{ - size_t len, offset, end; - struct iovec iov[2]; - ssize_t consumed; - - if (!ringbuf || fd < 0) - return -1; - - /* Determine how much data is available */ - len = ringbuf->in - ringbuf->out; - if (!len) - return 0; - - /* Grab data from buffer starting at offset until the end */ - offset = ringbuf->out & (ringbuf->size - 1); - end = minsize(len, ringbuf->size - offset); - - iov[0].iov_base = ringbuf->buffer + offset; - iov[0].iov_len = end; - - /* Use second vector for remainder from the beginning */ - iov[1].iov_base = ringbuf->buffer; - iov[1].iov_len = len - end; - - consumed = writev(fd, iov, 2); - if (consumed < 0) - return -1; - - ringbuf->out += consumed; - - if (ringbuf->out == ringbuf->in) { - ringbuf->in = RINGBUF_RESET; - ringbuf->out = RINGBUF_RESET; - } - - return consumed; -} - -/** - * l_ringbuf_avail: - * @ringbuf: Ring Buffer object - * - * Returns: Number of unoccupied bytes in the ring buffer - **/ -LIB_EXPORT size_t l_ringbuf_avail(struct l_ringbuf *ringbuf) -{ - if (!ringbuf) - return 0; - - return ringbuf->size - ringbuf->in + ringbuf->out; -} - -/** - * l_ringbuf_printf: - * @ringbuf: Ring Buffer object - * @format: printf-style format string - * - * Writes contents to the ring buffer using printf-style semantics - * - * Returns: Number of bytes written - **/ -LIB_EXPORT int l_ringbuf_printf(struct l_ringbuf *ringbuf, - const char *format, ...) -{ - va_list ap; - int len; - - va_start(ap, format); - len = l_ringbuf_vprintf(ringbuf, format, ap); - va_end(ap); - - return len; -} - -/** - * l_ringbuf_printf: - * @ringbuf: Ring Buffer object - * @format: printf-style format string - * @ap: variable argument list - * - * Writes contents to the ring buffer using printf-style semantics - * - * Returns: Number of bytes written - **/ -LIB_EXPORT int l_ringbuf_vprintf(struct l_ringbuf *ringbuf, - const char *format, va_list ap) -{ - size_t avail, offset, end; - char *str; - int len; - - if (!ringbuf || !format) - return -1; - - /* Determine maximum length available for string */ - avail = ringbuf->size - ringbuf->in + ringbuf->out; - if (!avail) - return -1; - - len = vasprintf(&str, format, ap); - if (len < 0) - return -1; - - if ((size_t) len > avail) { - l_free(str); - return -1; - } - - /* Determine possible length of string before wrapping */ - offset = ringbuf->in & (ringbuf->size - 1); - end = minsize((size_t) len, ringbuf->size - offset); - memcpy(ringbuf->buffer + offset, str, end); - - if (ringbuf->in_tracing) - ringbuf->in_tracing(ringbuf->buffer + offset, end, - ringbuf->in_data); - - if (len - end > 0) { - /* Put the remainder of string at the beginning */ - memcpy(ringbuf->buffer, str + end, len - end); - - if (ringbuf->in_tracing) - ringbuf->in_tracing(ringbuf->buffer, len - end, - ringbuf->in_data); - } - - l_free(str); - - ringbuf->in += len; - - return len; -} - -/** - * l_ringbuf_read: - * @ringbuf: Ring Buffer object - * @fd: file descriptor to read from - * - * Reads data from a file descriptor given by @fd into the ring buffer. - * - * Returns: Number of bytes read or -1 if the read failed. - **/ -LIB_EXPORT ssize_t l_ringbuf_read(struct l_ringbuf *ringbuf, int fd) -{ - size_t avail, offset, end; - struct iovec iov[2]; - ssize_t consumed; - - if (!ringbuf || fd < 0) - return -1; - - /* Determine how much can actually be consumed */ - avail = ringbuf->size - ringbuf->in + ringbuf->out; - if (!avail) - return -1; - - /* Determine how much to consume before wrapping */ - offset = ringbuf->in & (ringbuf->size - 1); - end = minsize(avail, ringbuf->size - offset); - - iov[0].iov_base = ringbuf->buffer + offset; - iov[0].iov_len = end; - - /* Now put the remainder into the second vector */ - iov[1].iov_base = ringbuf->buffer; - iov[1].iov_len = avail - end; - - consumed = readv(fd, iov, 2); - if (consumed < 0) - return -1; - - if (ringbuf->in_tracing) { - size_t len = minsize((size_t) consumed, end); - - ringbuf->in_tracing(ringbuf->buffer + offset, len, - ringbuf->in_data); - - if (consumed - len > 0) - ringbuf->in_tracing(ringbuf->buffer, consumed - len, - ringbuf->in_data); - } - - ringbuf->in += consumed; - - return consumed; -} diff --git a/ell/ringbuf.h b/ell/ringbuf.h deleted file mode 100644 index 846f7a5..0000000 --- a/ell/ringbuf.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2015 Intel Corporation. All rights reserved. - * - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_RINGBUF_H -#define __ELL_RINGBUF_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*l_ringbuf_tracing_func_t)(const void *buf, size_t count, - void *user_data); - -struct l_ringbuf; - -struct l_ringbuf *l_ringbuf_new(size_t size); -void l_ringbuf_free(struct l_ringbuf *ringbuf); - -bool l_ringbuf_set_input_tracing(struct l_ringbuf *ringbuf, - l_ringbuf_tracing_func_t callback, void *user_data); - -size_t l_ringbuf_capacity(struct l_ringbuf *ringbuf); - -size_t l_ringbuf_len(struct l_ringbuf *ringbuf); -size_t l_ringbuf_drain(struct l_ringbuf *ringbuf, size_t count); -void *l_ringbuf_peek(struct l_ringbuf *ringbuf, size_t offset, - size_t *len_nowrap); -ssize_t l_ringbuf_write(struct l_ringbuf *ringbuf, int fd); - -size_t l_ringbuf_avail(struct l_ringbuf *ringbuf); -int l_ringbuf_printf(struct l_ringbuf *ringbuf, const char *format, ...) - __attribute__((format(printf, 2, 3))); -int l_ringbuf_vprintf(struct l_ringbuf *ringbuf, const char *format, - va_list ap); -ssize_t l_ringbuf_read(struct l_ringbuf *ringbuf, int fd); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_RINGBUF_H */ diff --git a/ell/settings.c b/ell/settings.c deleted file mode 100644 index 4ab0bf5..0000000 --- a/ell/settings.c +++ /dev/null @@ -1,1437 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#if __STDC_VERSION__ <= 199409L -#define _DEFAULT_SOURCE /* for strto{u}ll() */ -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "strv.h" -#include "utf8.h" -#include "string.h" -#include "queue.h" -#include "settings.h" -#include "private.h" -#include "missing.h" -#include "pem-private.h" - -struct setting_data { - char *key; - char *value; -}; - -struct embedded_group_data { - char *name; - char type[32]; - size_t len; - char data[0]; -}; - -struct group_data { - char *name; - struct l_queue *settings; -}; - -struct l_settings { - l_settings_debug_cb_t debug_handler; - l_settings_destroy_cb_t debug_destroy; - void *debug_data; - struct l_queue *groups; - struct l_queue *embedded_groups; -}; - -static void setting_destroy(void *data) -{ - struct setting_data *pair = data; - - l_free(pair->key); - explicit_bzero(pair->value, strlen(pair->value)); - l_free(pair->value); - l_free(pair); -} - -static void group_destroy(void *data) -{ - struct group_data *group = data; - - l_free(group->name); - l_queue_destroy(group->settings, setting_destroy); - - l_free(group); -} - -static void embedded_group_destroy(void *data) -{ - struct embedded_group_data *group = data; - - l_free(group->name); - l_free(group); -} - -LIB_EXPORT struct l_settings *l_settings_new(void) -{ - struct l_settings *settings; - - settings = l_new(struct l_settings, 1); - settings->groups = l_queue_new(); - settings->embedded_groups = l_queue_new(); - - return settings; -} - -LIB_EXPORT void l_settings_free(struct l_settings *settings) -{ - if (unlikely(!settings)) - return; - - if (settings->debug_destroy) - settings->debug_destroy(settings->debug_data); - - l_queue_destroy(settings->groups, group_destroy); - l_queue_destroy(settings->embedded_groups, embedded_group_destroy); - - l_free(settings); -} - -static char *unescape_value(const char *value) -{ - char *ret; - char *n; - const char *o; - - ret = l_new(char, strlen(value) + 1); - - for (n = ret, o = value; *o; o++, n++) { - if (*o != '\\') { - *n = *o; - continue; - } - - o += 1; - - switch (*o) { - case 's': - *n = ' '; - break; - case 'n': - *n = '\n'; - break; - case 't': - *n = '\t'; - break; - case 'r': - *n = '\r'; - break; - case '\\': - *n = '\\'; - break; - default: - explicit_bzero(ret, n - ret); - l_free(ret); - return NULL; - } - } - - return ret; -} - -static char *escape_value(const char *value) -{ - size_t i; - size_t j; - char *ret; - bool lead_whitespace; - - for (i = 0, j = 0, lead_whitespace = true; value[i]; i++) { - switch (value[i]) { - case ' ': - case '\t': - if (lead_whitespace) - j += 1; - - break; - case '\n': - case '\r': - case '\\': - j += 1; - /* fall through */ - default: - lead_whitespace = false; - } - } - - ret = l_malloc(i + j + 1); - - for (i = 0, j = 0, lead_whitespace = true; value[i]; i++) { - switch (value[i]) { - case ' ': - if (lead_whitespace) { - ret[j++] = '\\'; - ret[j++] = 's'; - } else - ret[j++] = value[i]; - - break; - case '\t': - if (lead_whitespace) { - ret[j++] = '\\'; - ret[j++] = 't'; - } else - ret[j++] = value[i]; - - break; - case '\n': - ret[j++] = '\\'; - ret[j++] = 'n'; - lead_whitespace = false; - break; - case '\r': - ret[j++] = '\\'; - ret[j++] = 'r'; - lead_whitespace = false; - break; - case '\\': - ret[j++] = '\\'; - ret[j++] = '\\'; - lead_whitespace = false; - break; - default: - ret[j++] = value[i]; - lead_whitespace = false; - } - } - - ret[j] = '\0'; - - return ret; -} - -static ssize_t parse_pem(const char *data, size_t len) -{ - const char *ptr; - const char *end; - size_t count = 0; - - ptr = data; - end = data + len; - - while (ptr && ptr < end) { - const char *pem_start = ptr; - - if (!pem_next(ptr, len, NULL, NULL, &ptr, true)) { - if (ptr) - return -EINVAL; - - break; - } - - len -= ptr - pem_start; - count += ptr - pem_start; - } - - return count; -} - -struct group_extension { - char *name; - ssize_t (*parse)(const char *data, size_t len); -}; - -static const struct group_extension pem_extension = { - .name = "pem", - .parse = parse_pem, -}; - -static const struct group_extension *extensions[] = { - &pem_extension, - NULL -}; - -static const struct group_extension *find_group_extension(const char *type, - size_t len) -{ - unsigned int i; - - for (i = 0; extensions[i]; i++) { - if (!strncmp(type, extensions[i]->name, len)) - return extensions[i]; - } - - return NULL; -} - -static ssize_t parse_embedded_group(struct l_settings *setting, - const char *data, - size_t line_len, size_t len, - size_t line) -{ - struct embedded_group_data *group; - const struct group_extension *ext; - const char *ptr; - const char *type; - size_t type_len; - const char *name; - size_t name_len; - ssize_t bytes; - - /* Must be at least [@a@b] */ - if (line_len < 6) - goto invalid_group; - - /* caller checked data[1] == '@', next char is type */ - type = data + 2; - - ptr = memchr(type, '@', line_len - 2); - - type_len = ptr - type; - - if (!ptr || type_len > 31 || type_len < 1) - goto invalid_group; - - if (ptr + 1 > data + line_len) - goto invalid_group; - - name = ptr + 1; - - /* subtract [@@ + type */ - ptr = memchr(name, ']', line_len - 3 - type_len); - - name_len = ptr - name; - - if (!ptr || name_len < 1) - goto invalid_group; - - ext = find_group_extension(type, type_len); - if (!ext) - goto invalid_group; - - if (ptr + 2 > data + len) { - l_util_debug(setting->debug_handler, setting->debug_data, - "Embedded group had no payload"); - return -EINVAL; - } - - bytes = ext->parse(ptr + 2, len - line_len); - if (bytes < 0) { - l_util_debug(setting->debug_handler, setting->debug_data, - "Failed to parse embedded group data"); - return -EINVAL; - } - - group = l_malloc(sizeof(struct embedded_group_data) + bytes + 1); - - group->name = l_strndup(name, name_len); - - memcpy(group->type, type, type_len); - group->type[type_len] = '\0'; - - group->len = bytes; - memcpy(group->data, ptr + 2, bytes); - group->data[bytes] = '\0'; - - l_queue_push_tail(setting->embedded_groups, group); - - return bytes; - -invalid_group: - l_util_debug(setting->debug_handler, setting->debug_data, - "Invalid embedded group at line %zd", line); - - return -EINVAL; -} - -static bool parse_group(struct l_settings *settings, const char *data, - size_t len, size_t line) -{ - size_t i = 1; - size_t end; - struct group_data *group; - - while (i < len && data[i] != ']') { - if (l_ascii_isprint(data[i]) == false || data[i] == '[') { - l_util_debug(settings->debug_handler, - settings->debug_data, - "Invalid group name at line %zd", line); - return false; - } - - i += 1; - } - - if (i >= len) { - l_util_debug(settings->debug_handler, settings->debug_data, - "Unterminated group name at line %zd", line); - return false; - } - - end = i; - i += 1; - - while (i < len && l_ascii_isblank(data[i])) - i += 1; - - if (i != len) { - l_util_debug(settings->debug_handler, settings->debug_data, - "Junk characters at the end of line %zd", line); - return false; - } - - group = l_new(struct group_data, 1); - group->name = l_strndup(data + 1, end - 1); - group->settings = l_queue_new(); - - l_queue_push_tail(settings->groups, group); - - return true; -} - -static bool validate_key_character(char c) -{ - if (l_ascii_isalnum(c)) - return true; - - if (c == '_' || c == '-' || c == '.') - return true; - - return false; -} - -static unsigned int parse_key(struct l_settings *settings, const char *data, - size_t len, size_t line) -{ - unsigned int i; - unsigned int end; - struct group_data *group; - struct setting_data *pair; - - for (i = 0; i < len; i++) { - if (validate_key_character(data[i])) - continue; - - if (l_ascii_isblank(data[i])) - break; - - l_util_debug(settings->debug_handler, settings->debug_data, - "Invalid character in Key on line %zd", line); - - return 0; - } - - end = i; - - /* Make sure the rest of the characters are blanks */ - while (i < len) { - if (l_ascii_isblank(data[i++])) - continue; - - l_util_debug(settings->debug_handler, settings->debug_data, - "Garbage after Key on line %zd", line); - - return 0; - } - - group = l_queue_peek_tail(settings->groups); - pair = l_new(struct setting_data, 1); - pair->key = l_strndup(data, end); - l_queue_push_head(group->settings, pair); - - return end; -} - -static bool parse_value(struct l_settings *settings, const char *data, - size_t len, size_t line) -{ - unsigned int end = len; - struct group_data *group; - struct setting_data *pair; - - group = l_queue_peek_tail(settings->groups); - pair = l_queue_pop_head(group->settings); - - if (!l_utf8_validate(data, len, NULL)) { - l_util_debug(settings->debug_handler, settings->debug_data, - "Invalid UTF8 in value on line: %zd", line); - - l_free(pair->key); - l_free(pair); - - return false; - } - - pair->value = l_strndup(data, end); - l_queue_push_tail(group->settings, pair); - - return true; -} - -static bool parse_keyvalue(struct l_settings *settings, const char *data, - size_t len, size_t line) -{ - const char *equal = memchr(data, '=', len); - - if (!equal) { - l_util_debug(settings->debug_handler, settings->debug_data, - "Delimiter '=' not found on line: %zd", line); - return false; - } - - if (equal == data) { - l_util_debug(settings->debug_handler, settings->debug_data, - "Empty key on line: %zd", line); - return false; - } - - if (!parse_key(settings, data, equal - data, line)) - return false; - - equal += 1; - while (equal < data + len && l_ascii_isblank(*equal)) - equal += 1; - - return parse_value(settings, equal, len - (equal - data), line); -} - -LIB_EXPORT bool l_settings_load_from_data(struct l_settings *settings, - const char *data, size_t len) -{ - size_t pos = 0; - bool r = true; - bool has_group = false; - const char *eol; - size_t line = 1; - size_t line_len; - - if (unlikely(!settings || !data || !len)) - return false; - - while (pos < len && r) { - if (l_ascii_isblank(data[pos])) { - pos += 1; - continue; - } - - if (data[pos] == '\n') { - line += 1; - pos += 1; - continue; - } - - eol = memchr(data + pos, '\n', len - pos); - if (!eol) - eol = data + len; - - line_len = eol - data - pos; - - if (line_len > 1 && data[pos] == '[' && data[pos + 1] == '@') { - ssize_t ret; - - ret = parse_embedded_group(settings, data + pos, - line_len, len - pos, - line); - if (ret < 0) - return false; - - /* - * This is the offset for the actual raw data, the - * group line will be offset below - */ - pos += ret; - } else if (data[pos] == '[') { - r = parse_group(settings, data + pos, line_len, line); - if (r) - has_group = true; - } else if (data[pos] != '#') { - if (!has_group) - return false; - - r = parse_keyvalue(settings, data + pos, line_len, - line); - } - - pos += line_len; - } - - return r; -} - -LIB_EXPORT char *l_settings_to_data(const struct l_settings *settings, - size_t *len) -{ - struct l_string *buf; - char *ret; - const struct l_queue_entry *group_entry; - - if (unlikely(!settings)) - return NULL; - - buf = l_string_new(255); - - group_entry = l_queue_get_entries(settings->groups); - while (group_entry) { - struct group_data *group = group_entry->data; - const struct l_queue_entry *setting_entry; - - l_string_append_printf(buf, "[%s]\n", group->name); - - setting_entry = l_queue_get_entries(group->settings); - - while (setting_entry) { - struct setting_data *setting = setting_entry->data; - - l_string_append_printf(buf, "%s=%s\n", - setting->key, setting->value); - setting_entry = setting_entry->next; - } - - if (group_entry->next) - l_string_append_c(buf, '\n'); - - group_entry = group_entry->next; - } - - group_entry = l_queue_get_entries(settings->embedded_groups); - - if (group_entry && l_queue_length(settings->groups) > 0) - l_string_append_c(buf, '\n'); - - while (group_entry) { - struct embedded_group_data *group = group_entry->data; - - l_string_append_printf(buf, "[@%s@%s]\n%s", - group->type, - group->name, - group->data); - if (group_entry->next) - l_string_append_c(buf, '\n'); - - group_entry = group_entry->next; - } - - ret = l_string_unwrap(buf); - - if (len) - *len = strlen(ret); - - return ret; -} - -LIB_EXPORT bool l_settings_load_from_file(struct l_settings *settings, - const char *filename) -{ - int fd; - struct stat st; - char *data; - bool r; - - if (unlikely(!settings || !filename)) - return false; - - fd = open(filename, O_RDONLY); - if (fd < 0) { - l_util_debug(settings->debug_handler, settings->debug_data, - "Could not open %s (%s)", filename, - strerror(errno)); - return false; - } - - if (fstat(fd, &st) < 0) { - l_util_debug(settings->debug_handler, settings->debug_data, - "Could not stat %s (%s)", filename, - strerror(errno)); - close(fd); - - return false; - } - - /* Nothing to do, assume success */ - if (st.st_size == 0) { - close(fd); - return true; - } - - data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) { - l_util_debug(settings->debug_handler, settings->debug_data, - "Could not mmap %s (%s)", filename, - strerror(errno)); - close(fd); - - return false; - } - - r = l_settings_load_from_data(settings, data, st.st_size); - - munmap(data, st.st_size); - close(fd); - - return r; -} - -LIB_EXPORT bool l_settings_set_debug(struct l_settings *settings, - l_settings_debug_cb_t callback, - void *user_data, - l_settings_destroy_cb_t destroy) -{ - if (unlikely(!settings)) - return false; - - if (settings->debug_destroy) - settings->debug_destroy(settings->debug_data); - - settings->debug_handler = callback; - settings->debug_destroy = destroy; - settings->debug_data = user_data; - - return true; -} - -static bool group_match(const void *a, const void *b) -{ - const struct group_data *group = a; - const char *name = b; - - return !strcmp(group->name, name); -} - -struct gather_data { - int cur; - char **v; -}; - -static void gather_groups(void *data, void *user_data) -{ - struct group_data *group_data = data; - struct gather_data *gather = user_data; - - gather->v[gather->cur++] = l_strdup(group_data->name); -} - -LIB_EXPORT char **l_settings_get_groups(const struct l_settings *settings) -{ - char **ret; - struct gather_data gather; - - if (unlikely(!settings)) - return NULL; - - ret = l_new(char *, l_queue_length(settings->groups) + 1); - gather.v = ret; - gather.cur = 0; - - l_queue_foreach(settings->groups, gather_groups, &gather); - - return ret; -} - -LIB_EXPORT bool l_settings_has_group(const struct l_settings *settings, - const char *group_name) -{ - struct group_data *group; - - if (unlikely(!settings)) - return false; - - group = l_queue_find(settings->groups, group_match, group_name); - - return !!group; -} - -static bool key_match(const void *a, const void *b) -{ - const struct setting_data *setting = a; - const char *key = b; - - return !strcmp(setting->key, key); -} - -static void gather_keys(void *data, void *user_data) -{ - struct setting_data *setting_data = data; - struct gather_data *gather = user_data; - - gather->v[gather->cur++] = l_strdup(setting_data->key); -} - -LIB_EXPORT char **l_settings_get_keys(const struct l_settings *settings, - const char *group_name) -{ - char **ret; - struct group_data *group_data; - struct gather_data gather; - - if (unlikely(!settings)) - return NULL; - - group_data = l_queue_find(settings->groups, group_match, group_name); - if (!group_data) - return NULL; - - ret = l_new(char *, l_queue_length(group_data->settings) + 1); - gather.v = ret; - gather.cur = 0; - - l_queue_foreach(group_data->settings, gather_keys, &gather); - - return ret; -} - -LIB_EXPORT bool l_settings_has_key(const struct l_settings *settings, - const char *group_name, const char *key) -{ - struct group_data *group; - struct setting_data *setting; - - if (unlikely(!settings)) - return false; - - group = l_queue_find(settings->groups, group_match, group_name); - if (!group) - return false; - - setting = l_queue_find(group->settings, key_match, key); - - return !!setting; -} - -LIB_EXPORT const char *l_settings_get_value(const struct l_settings *settings, - const char *group_name, - const char *key) -{ - struct group_data *group; - struct setting_data *setting; - - if (unlikely(!settings)) - return NULL; - - group = l_queue_find(settings->groups, group_match, group_name); - if (!group) - return NULL; - - setting = l_queue_find(group->settings, key_match, key); - if (!setting) - return NULL; - - return setting->value; -} - -static bool validate_group_name(const char *group_name) -{ - int i; - - for (i = 0; group_name[i]; i++) { - if (!l_ascii_isprint(group_name[i])) - return false; - - if (group_name[i] == ']' || group_name[i] == '[') - return false; - } - - return true; -} - -static bool validate_key(const char *key) -{ - int i; - - for (i = 0; key[i]; i++) { - if (!validate_key_character(key[i])) - return false; - } - - return true; -} - -static bool set_value(struct l_settings *settings, const char *group_name, - const char *key, char *value) -{ - struct group_data *group; - struct setting_data *pair; - - if (!validate_group_name(group_name)) { - l_util_debug(settings->debug_handler, settings->debug_data, - "Invalid group name %s", group_name); - l_free(value); - - return false; - } - - if (!validate_key(key)) { - l_util_debug(settings->debug_handler, settings->debug_data, - "Invalid key %s", key); - l_free(value); - - return false; - } - - group = l_queue_find(settings->groups, group_match, group_name); - if (!group) { - group = l_new(struct group_data, 1); - group->name = l_strdup(group_name); - group->settings = l_queue_new(); - - l_queue_push_tail(settings->groups, group); - goto add_pair; - } - - pair = l_queue_find(group->settings, key_match, key); - if (!pair) { -add_pair: - pair = l_new(struct setting_data, 1); - pair->key = l_strdup(key); - pair->value = value; - l_queue_push_tail(group->settings, pair); - - return true; - } - - l_free(pair->value); - pair->value = value; - - return true; -} - -LIB_EXPORT bool l_settings_set_value(struct l_settings *settings, - const char *group_name, const char *key, - const char *value) -{ - if (unlikely(!settings || !value)) - return false; - - return set_value(settings, group_name, key, l_strdup(value)); -} - -LIB_EXPORT bool l_settings_get_bool(const struct l_settings *settings, - const char *group_name, const char *key, - bool *out) -{ - const char *value; - - value = l_settings_get_value(settings, group_name, key); - if (!value) - return false; - - if (!strcasecmp(value, "true") || !strcmp(value, "1")) { - if (out) - *out = true; - - return true; - } - - if (!strcasecmp(value, "false") || !strcmp(value, "0")) { - if (out) - *out = false; - - return true; - } - - l_util_debug(settings->debug_handler, settings->debug_data, - "Could not interpret %s as a bool", value); - - return false; -} - -LIB_EXPORT bool l_settings_set_bool(struct l_settings *settings, - const char *group_name, const char *key, - bool in) -{ - static const char *true_str = "true"; - static const char *false_str = "false"; - const char *v; - - if (in == false) - v = false_str; - else - v = true_str; - - return l_settings_set_value(settings, group_name, key, v); -} - -LIB_EXPORT bool l_settings_get_int(const struct l_settings *settings, - const char *group_name, - const char *key, int *out) -{ - const char *value = l_settings_get_value(settings, group_name, key); - long int r; - int t; - char *endp; - - if (!value) - return false; - - if (*value == '\0') - goto error; - - errno = 0; - - t = r = strtol(value, &endp, 10); - if (*endp != '\0') - goto error; - - if (unlikely(errno == ERANGE || r != t)) - goto error; - - if (out) - *out = r; - - return true; - -error: - l_util_debug(settings->debug_handler, settings->debug_data, - "Could not interpret %s as an int", value); - - return false; -} - -LIB_EXPORT bool l_settings_set_int(struct l_settings *settings, - const char *group_name, const char *key, - int in) -{ - char buf[64]; - - snprintf(buf, sizeof(buf), "%d", in); - - return l_settings_set_value(settings, group_name, key, buf); -} - -LIB_EXPORT bool l_settings_get_uint(const struct l_settings *settings, - const char *group_name, const char *key, - unsigned int *out) -{ - const char *value = l_settings_get_value(settings, group_name, key); - unsigned long int r; - unsigned int t; - char *endp; - - if (!value) - return false; - - if (*value == '\0') - goto error; - - errno = 0; - - t = r = strtoul(value, &endp, 10); - if (*endp != '\0') - goto error; - - if (unlikely(errno == ERANGE || r != t)) - goto error; - - if (out) - *out = r; - - return true; - -error: - l_util_debug(settings->debug_handler, settings->debug_data, - "Could not interpret %s as a uint", value); - - return false; -} - -LIB_EXPORT bool l_settings_set_uint(struct l_settings *settings, - const char *group_name, const char *key, - unsigned int in) -{ - char buf[64]; - - snprintf(buf, sizeof(buf), "%u", in); - - return l_settings_set_value(settings, group_name, key, buf); -} - -LIB_EXPORT bool l_settings_get_int64(const struct l_settings *settings, - const char *group_name, const char *key, - int64_t *out) -{ - const char *value = l_settings_get_value(settings, group_name, key); - int64_t r; - char *endp; - - if (!value) - return false; - - if (*value == '\0') - goto error; - - errno = 0; - - r = strtoll(value, &endp, 10); - if (*endp != '\0') - goto error; - - if (unlikely(errno == ERANGE)) - goto error; - - if (out) - *out = r; - - return true; - -error: - l_util_debug(settings->debug_handler, settings->debug_data, - "Could not interpret %s as an int64", value); - - return false; -} - -LIB_EXPORT bool l_settings_set_int64(struct l_settings *settings, - const char *group_name, const char *key, - int64_t in) -{ - char buf[64]; - - snprintf(buf, sizeof(buf), "%" PRId64, in); - - return l_settings_set_value(settings, group_name, key, buf); -} - -LIB_EXPORT bool l_settings_get_uint64(const struct l_settings *settings, - const char *group_name, const char *key, - uint64_t *out) -{ - const char *value = l_settings_get_value(settings, group_name, key); - uint64_t r; - char *endp; - - if (!value) - return false; - - if (*value == '\0') - goto error; - - errno = 0; - - r = strtoull(value, &endp, 10); - if (*endp != '\0') - goto error; - - if (unlikely(errno == ERANGE)) - goto error; - - if (out) - *out = r; - - return true; - -error: - l_util_debug(settings->debug_handler, settings->debug_data, - "Could not interpret %s as a uint64", value); - - return false; -} - -LIB_EXPORT bool l_settings_set_uint64(struct l_settings *settings, - const char *group_name, const char *key, - uint64_t in) -{ - char buf[64]; - - snprintf(buf, sizeof(buf), "%" PRIu64, in); - - return l_settings_set_value(settings, group_name, key, buf); -} - -LIB_EXPORT char *l_settings_get_string(const struct l_settings *settings, - const char *group_name, const char *key) -{ - const char *value = l_settings_get_value(settings, group_name, key); - - if (!value) - return NULL; - - return unescape_value(value); -} - -LIB_EXPORT bool l_settings_set_string(struct l_settings *settings, - const char *group_name, const char *key, - const char *value) -{ - char *buf; - - if (unlikely(!settings || !value)) - return false; - - buf = escape_value(value); - - return set_value(settings, group_name, key, buf); -} - -LIB_EXPORT char **l_settings_get_string_list(const struct l_settings *settings, - const char *group_name, - const char *key, - const char delimiter) -{ - const char *value = l_settings_get_value(settings, group_name, key); - char *str; - char **ret; - - if (!value) - return NULL; - - str = unescape_value(value); - if (str == NULL) - return NULL; - - ret = l_strsplit(str, delimiter); - l_free(str); - - return ret; -} - -LIB_EXPORT bool l_settings_set_string_list(struct l_settings *settings, - const char *group_name, const char *key, - char **value, char delimiter) -{ - char *buf; - char *tmp; - - if (unlikely(!settings || !value)) - return false; - - tmp = l_strjoinv(value, delimiter); - buf = escape_value(tmp); - l_free(tmp); - - return set_value(settings, group_name, key, buf); -} - -LIB_EXPORT bool l_settings_get_double(const struct l_settings *settings, - const char *group_name, const char *key, - double *out) -{ - const char *value = l_settings_get_value(settings, group_name, key); - char *endp; - double r; - - if (!value) - return NULL; - - if (*value == '\0') - goto error; - - errno = 0; - - r = strtod(value, &endp); - if (*endp != '\0') - goto error; - - if (unlikely(errno == ERANGE)) - goto error; - - if (out) - *out = r; - - return true; - -error: - l_util_debug(settings->debug_handler, settings->debug_data, - "Could not interpret %s as a double", value); - - return false; -} - -LIB_EXPORT bool l_settings_set_double(struct l_settings *settings, - const char *group_name, const char *key, - double in) -{ - L_AUTO_FREE_VAR(char *, buf); - buf = NULL; - - buf = l_strdup_printf("%f", in); - - return l_settings_set_value(settings, group_name, key, buf); -} - -LIB_EXPORT bool l_settings_get_float(const struct l_settings *settings, - const char *group_name, const char *key, - float *out) -{ - const char *value = l_settings_get_value(settings, group_name, key); - char *endp; - float r; - - if (!value) - return NULL; - - if (*value == '\0') - goto error; - - errno = 0; - - r = strtof(value, &endp); - if (*endp != '\0') - goto error; - - if (unlikely(errno == ERANGE)) - goto error; - - if (out) - *out = r; - - return true; - -error: - l_util_debug(settings->debug_handler, settings->debug_data, - "Could not interpret %s as a float", value); - - return false; -} - -LIB_EXPORT bool l_settings_set_float(struct l_settings *settings, - const char *group_name, const char *key, - float in) -{ - L_AUTO_FREE_VAR(char *, buf); - buf = NULL; - - buf = l_strdup_printf("%f", in); - - return l_settings_set_value(settings, group_name, key, buf); -} - -LIB_EXPORT bool l_settings_remove_group(struct l_settings *settings, - const char *group_name) -{ - struct group_data *group; - - if (unlikely(!settings)) - return false; - - group = l_queue_remove_if(settings->groups, group_match, group_name); - if (!group) - return false; - - group_destroy(group); - - return true; -} - -LIB_EXPORT bool l_settings_remove_key(struct l_settings *settings, - const char *group_name, - const char *key) -{ - struct group_data *group; - struct setting_data *setting; - - if (unlikely(!settings)) - return false; - - group = l_queue_find(settings->groups, group_match, group_name); - if (!group) - return false; - - setting = l_queue_remove_if(group->settings, key_match, key); - if (!setting) - return false; - - setting_destroy(setting); - - return true; -} - -static void gather_embedded_groups(void *data, void *user_data) -{ - struct embedded_group_data *group_data = data; - struct gather_data *gather = user_data; - - gather->v[gather->cur++] = l_strdup(group_data->name); -} - -LIB_EXPORT char **l_settings_get_embedded_groups(struct l_settings *settings) -{ - char **ret; - struct gather_data gather; - - if (unlikely(!settings)) - return NULL; - - ret = l_new(char *, l_queue_length(settings->groups) + 1); - gather.v = ret; - gather.cur = 0; - - l_queue_foreach(settings->embedded_groups, gather_embedded_groups, - &gather); - - return ret; -} - -static bool embedded_group_match(const void *a, const void *b) -{ - const struct embedded_group_data *group = a; - const char *name = b; - - return !strcmp(group->name, name); -} - -LIB_EXPORT bool l_settings_has_embedded_group(struct l_settings *settings, - const char *group) -{ - struct embedded_group_data *group_data; - - if (unlikely(!settings)) - return false; - - group_data = l_queue_find(settings->embedded_groups, - embedded_group_match, group); - - return group_data != NULL; -} - -LIB_EXPORT const char *l_settings_get_embedded_value( - struct l_settings *settings, - const char *group_name, - const char **out_type) -{ - struct embedded_group_data *group; - - if (unlikely(!settings)) - return false; - - group = l_queue_find(settings->embedded_groups, - embedded_group_match, group_name); - if (!group) - return NULL; - - if (out_type) - *out_type = group->type; - - return group->data; -} diff --git a/ell/settings.h b/ell/settings.h deleted file mode 100644 index e4203af..0000000 --- a/ell/settings.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_SETTINGS_H -#define __ELL_SETTINGS_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_settings; - -typedef void (*l_settings_debug_cb_t) (const char *str, void *user_data); -typedef void (*l_settings_destroy_cb_t) (void *user_data); - -struct l_settings *l_settings_new(void); -void l_settings_free(struct l_settings *settings); - -bool l_settings_load_from_data(struct l_settings *settings, - const char *data, size_t len); -char *l_settings_to_data(const struct l_settings *settings, size_t *len); - -bool l_settings_load_from_file(struct l_settings *settings, - const char *filename); - -bool l_settings_set_debug(struct l_settings *settings, - l_settings_debug_cb_t callback, - void *user_data, - l_settings_destroy_cb_t destroy); - -char **l_settings_get_groups(const struct l_settings *settings); -char **l_settings_get_keys(const struct l_settings *settings, - const char *group_name); - -bool l_settings_has_group(const struct l_settings *settings, - const char *group_name); -bool l_settings_has_key(const struct l_settings *settings, - const char *group_name, const char *key); - -const char *l_settings_get_value(const struct l_settings *settings, - const char *group_name, - const char *key); -bool l_settings_set_value(struct l_settings *settings, const char *group_name, - const char *key, const char *value); - -bool l_settings_get_bool(const struct l_settings *settings, - const char *group_name, - const char *key, bool *out); -bool l_settings_set_bool(struct l_settings *settings, const char *group_name, - const char *key, bool in); - -bool l_settings_get_int(const struct l_settings *settings, - const char *group_name, const char *key, int *out); -bool l_settings_set_int(struct l_settings *settings, const char *group_name, - const char *key, int in); - -bool l_settings_get_uint(const struct l_settings *settings, - const char *group_name, - const char *key, unsigned int *out); -bool l_settings_set_uint(struct l_settings *settings, const char *group_name, - const char *key, unsigned int in); - -bool l_settings_get_int64(const struct l_settings *settings, - const char *group_name, - const char *key, int64_t *out); -bool l_settings_set_int64(struct l_settings *settings, const char *group_name, - const char *key, int64_t in); - -bool l_settings_get_uint64(const struct l_settings *settings, - const char *group_name, - const char *key, uint64_t *out); -bool l_settings_set_uint64(struct l_settings *settings, const char *group_name, - const char *key, uint64_t in); - -char *l_settings_get_string(const struct l_settings *settings, - const char *group_name, const char *key); -bool l_settings_set_string(struct l_settings *settings, const char *group_name, - const char *key, const char *value); - -char **l_settings_get_string_list(const struct l_settings *settings, - const char *group_name, - const char *key, char delimiter); -bool l_settings_set_string_list(struct l_settings *settings, - const char *group_name, - const char *key, char **list, - char delimiter); - -bool l_settings_get_double(const struct l_settings *settings, - const char *group_name, - const char *key, double *out); -bool l_settings_set_double(struct l_settings *settings, const char *group_name, - const char *key, double in); - -bool l_settings_get_float(const struct l_settings *settings, - const char *group_name, - const char *key, float *out); -bool l_settings_set_float(struct l_settings *settings, const char *group_name, - const char *key, float in); - -bool l_settings_remove_key(struct l_settings *settings, const char *group_name, - const char *key); -bool l_settings_remove_group(struct l_settings *settings, - const char *group_name); - -char **l_settings_get_embedded_groups(struct l_settings *settings); -bool l_settings_has_embedded_group(struct l_settings *settings, - const char *group); -const char *l_settings_get_embedded_value(struct l_settings *settings, - const char *group_name, - const char **out_type); -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_SETTINGS_H */ diff --git a/ell/signal.c b/ell/signal.c deleted file mode 100644 index fc15c22..0000000 --- a/ell/signal.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "io.h" -#include "queue.h" -#include "signal.h" -#include "private.h" - -/** - * SECTION:signal - * @short_description: Unix signal support - * - * Unix signal support - */ - -/** - * l_signal: - * - * Opague object representing the signal. - */ -struct l_signal { - struct signal_desc *desc; - l_signal_notify_cb_t callback; - void *user_data; - l_signal_destroy_cb_t destroy; -}; - -struct signal_desc { - uint32_t signo; - struct l_queue *callbacks; -}; - -static struct l_io *signalfd_io = NULL; -static struct l_queue *signal_list = NULL; -static sigset_t signal_mask; - -static void handle_callback(struct signal_desc *desc) -{ - const struct l_queue_entry *entry; - - for (entry = l_queue_get_entries(desc->callbacks); entry; - entry = entry->next) { - struct l_signal *signal = entry->data; - - if (signal->callback) - signal->callback(signal->user_data); - } -} - -static bool desc_match_signo(const void *a, const void *b) -{ - const struct signal_desc *desc = a; - uint32_t signo = L_PTR_TO_UINT(b); - - return (desc->signo == signo); -} - -static bool signalfd_read_cb(struct l_io *io, void *user_data) -{ - int fd = l_io_get_fd(io); - struct signal_desc *desc; - struct signalfd_siginfo si; - ssize_t result; - - result = read(fd, &si, sizeof(si)); - if (result != sizeof(si)) - return true; - - desc = l_queue_find(signal_list, desc_match_signo, - L_UINT_TO_PTR(si.ssi_signo)); - if (desc) - handle_callback(desc); - - return true; -} - -static bool signalfd_add(int signo) -{ - int fd; - - if (!signalfd_io) { - fd = -1; - sigemptyset(&signal_mask); - } else - fd = l_io_get_fd(signalfd_io); - - sigaddset(&signal_mask, signo); - - fd = signalfd(fd, &signal_mask, SFD_CLOEXEC); - if (fd < 0) - return false; - - if (signalfd_io) - return true; - - signalfd_io = l_io_new(fd); - if (!signalfd_io) { - close(fd); - return false; - } - - l_io_set_close_on_destroy(signalfd_io, true); - - if (!l_io_set_read_handler(signalfd_io, signalfd_read_cb, NULL, NULL)) { - l_io_destroy(signalfd_io); - return false; - } - - signal_list = l_queue_new(); - - return true; -} - -static void signalfd_remove(int signo) -{ - if (!signalfd_io) - return; - - sigdelset(&signal_mask, signo); - - if (!sigisemptyset(&signal_mask)) { - signalfd(l_io_get_fd(signalfd_io), &signal_mask, SFD_CLOEXEC); - return; - } - - l_io_destroy(signalfd_io); - signalfd_io = NULL; - - l_queue_destroy(signal_list, NULL); - signal_list = NULL; -} - -/** - * l_signal_create: - * @callback: signal callback function - * @user_data: user data provided to signal callback function - * @destroy: destroy function for user data - * - * Create new signal callback handling for a given set of signals. - * - * Returns: a newly allocated #l_signal object - **/ -LIB_EXPORT struct l_signal *l_signal_create(uint32_t signo, - l_signal_notify_cb_t callback, - void *user_data, l_signal_destroy_cb_t destroy) -{ - struct l_signal *signal; - struct signal_desc *desc; - sigset_t mask, oldmask; - - if (signo <= 1 || signo >= _NSIG) - return NULL; - - signal = l_new(struct l_signal, 1); - signal->callback = callback; - signal->destroy = destroy; - signal->user_data = user_data; - - desc = l_queue_find(signal_list, desc_match_signo, - L_UINT_TO_PTR(signo)); - if (desc) - goto done; - - sigemptyset(&mask); - sigaddset(&mask, signo); - - if (sigprocmask(SIG_BLOCK, &mask, &oldmask) < 0) { - l_free(signal); - return NULL; - } - - if (!signalfd_add(signo)) { - sigprocmask(SIG_SETMASK, &oldmask, NULL); - l_free(signal); - return NULL; - } - - desc = l_new(struct signal_desc, 1); - desc->signo = signo; - desc->callbacks = l_queue_new(); - - l_queue_push_tail(signal_list, desc); - -done: - l_queue_push_tail(desc->callbacks, signal); - signal->desc = desc; - return signal; -} - -/** - * l_signal_remove: - * @signal: signal object - * - * Remove signal handling. - **/ -LIB_EXPORT void l_signal_remove(struct l_signal *signal) -{ - struct signal_desc *desc; - sigset_t mask; - - if (!signal) - return; - - desc = signal->desc; - l_queue_remove(desc->callbacks, signal); - - /* - * As long as the signal descriptor has callbacks registered, it is - * still needed to be active. - */ - if (!l_queue_isempty(desc->callbacks)) - goto done; - - if (!l_queue_remove(signal_list, desc)) - goto done; - - sigemptyset(&mask); - sigaddset(&mask, desc->signo); - - /* - * When the number of signals goes to zero, then this will close - * the signalfd file descriptor, otherwise it will only adjust the - * signal mask to account for the removed signal. - * - */ - signalfd_remove(desc->signo); - sigprocmask(SIG_UNBLOCK, &mask, NULL); - l_queue_destroy(desc->callbacks, NULL); - l_free(desc); - -done: - if (signal->destroy) - signal->destroy(signal->user_data); - - l_free(signal); -} diff --git a/ell/signal.h b/ell/signal.h deleted file mode 100644 index 1d98476..0000000 --- a/ell/signal.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_SIGNAL_H -#define __ELL_SIGNAL_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_signal; - -typedef void (*l_signal_notify_cb_t) (void *user_data); -typedef void (*l_signal_destroy_cb_t) (void *user_data); - -struct l_signal *l_signal_create(uint32_t signo, l_signal_notify_cb_t callback, - void *user_data, l_signal_destroy_cb_t destroy); -void l_signal_remove(struct l_signal *signal); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_SIGNAL_H */ diff --git a/ell/siphash-private.h b/ell/siphash-private.h deleted file mode 100644 index 02e9ed0..0000000 --- a/ell/siphash-private.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include - -void _siphash24(uint8_t out[8], const uint8_t *in, size_t inlen, - const uint8_t k[16]); diff --git a/ell/siphash.c b/ell/siphash.c deleted file mode 100644 index a37d228..0000000 --- a/ell/siphash.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "siphash-private.h" - -/* - * Based on public domain SipHash reference C implementation - * - * Written in 2012 by - * Jean-Philippe Aumasson - * Daniel J. Bernstein - * - */ - -#define ROTL(x,b) (uint64_t) (((x) << (b)) | ((x) >> (64 - (b)))) - -#define U32TO8_LE(p, v) \ - (p)[0] = (uint8_t) ((v)); \ - (p)[1] = (uint8_t) ((v) >> 8); \ - (p)[2] = (uint8_t) ((v) >> 16); \ - (p)[3] = (uint8_t) ((v) >> 24); - -#define U64TO8_LE(p, v) \ - U32TO8_LE((p), (uint32_t) ((v))); \ - U32TO8_LE((p) + 4, (uint32_t) ((v) >> 32)); - -#define U8TO64_LE(p) \ - (((uint64_t) ((p)[0])) | \ - ((uint64_t) ((p)[1]) << 8) | \ - ((uint64_t) ((p)[2]) << 16) | \ - ((uint64_t) ((p)[3]) << 24) | \ - ((uint64_t) ((p)[4]) << 32) | \ - ((uint64_t) ((p)[5]) << 40) | \ - ((uint64_t) ((p)[6]) << 48) | \ - ((uint64_t) ((p)[7]) << 56)) - -#define SIPROUND \ - do { \ - v0 += v1; v1=ROTL(v1, 13); \ - v1 ^= v0; v0=ROTL(v0, 32); \ - v2 += v3; v3=ROTL(v3, 16); \ - v3 ^= v2; \ - v0 += v3; v3=ROTL(v3, 21); \ - v3 ^= v0; \ - v2 += v1; v1=ROTL(v1, 17); \ - v1 ^= v2; v2=ROTL(v2, 32); \ - } while(0) - -void _siphash24(uint8_t out[8], const uint8_t *in, size_t inlen, - const uint8_t k[16]) -{ - /* "somepseudorandomlygeneratedbytes" */ - uint64_t v0 = 0x736f6d6570736575ULL; - uint64_t v1 = 0x646f72616e646f6dULL; - uint64_t v2 = 0x6c7967656e657261ULL; - uint64_t v3 = 0x7465646279746573ULL; - uint64_t b; - uint64_t k0 = U8TO64_LE(k); - uint64_t k1 = U8TO64_LE(k + 8); - uint64_t m; - const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); - const int left = inlen & 7; - - b = ((uint64_t) inlen) << 56; - v3 ^= k1; - v2 ^= k0; - v1 ^= k1; - v0 ^= k0; - - for (; in != end; in += 8) { - m = U8TO64_LE(in); - v3 ^= m; - SIPROUND; - SIPROUND; - v0 ^= m; - } - - switch (left) { - case 7: - b |= ((uint64_t) in[6]) << 48; - /* fall through */ - case 6: - b |= ((uint64_t) in[5]) << 40; - /* fall through */ - case 5: - b |= ((uint64_t) in[4]) << 32; - /* fall through */ - case 4: - b |= ((uint64_t) in[3]) << 24; - /* fall through */ - case 3: - b |= ((uint64_t) in[2]) << 16; - /* fall through */ - case 2: - b |= ((uint64_t) in[1]) << 8; - /* fall through */ - case 1: - b |= ((uint64_t) in[0]); - break; - case 0: - break; - } - - v3 ^= b; - SIPROUND; - SIPROUND; - v0 ^= b; - v2 ^= 0xff; - SIPROUND; - SIPROUND; - SIPROUND; - SIPROUND; - b = v0 ^ v1 ^ v2 ^ v3; - U64TO8_LE(out, b); -} diff --git a/ell/string.c b/ell/string.c deleted file mode 100644 index 37806e3..0000000 --- a/ell/string.c +++ /dev/null @@ -1,518 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "util.h" -#include "strv.h" -#include "string.h" -#include "private.h" - -/** - * SECTION:string - * @short_description: Growable string buffer - * - * Growable string buffer support - */ - -/** - * l_string: - * - * Opague object representing the string buffer. - */ -struct l_string { - size_t max; - size_t len; - char *str; -}; - -static inline size_t next_power(size_t len) -{ - size_t n = 1; - - if (len > SIZE_MAX / 2) - return SIZE_MAX; - - while (n < len) - n = n << 1; - - return n; -} - -static void grow_string(struct l_string *str, size_t extra) -{ - if (str->len + extra < str->max) - return; - - str->max = next_power(str->len + extra + 1); - str->str = l_realloc(str->str, str->max); -} - -/** - * l_string_new: - * @initial_length: Initial length of the groable string - * - * Create new growable string. If the @initial_length is 0, then a safe - * default is chosen. - * - * Returns: a newly allocated #l_string object. - **/ -LIB_EXPORT struct l_string *l_string_new(size_t initial_length) -{ - static const size_t DEFAULT_INITIAL_LENGTH = 127; - struct l_string *ret; - - ret = l_new(struct l_string, 1); - - if (initial_length == 0) - initial_length = DEFAULT_INITIAL_LENGTH; - - grow_string(ret, initial_length); - ret->str[0] = '\0'; - - return ret; -} - -/** - * l_string_free: - * @string: growable string object - * - * Free the growable string object and all associated data - **/ -LIB_EXPORT void l_string_free(struct l_string *string) -{ - if (unlikely(!string)) - return; - - l_free(string->str); - l_free(string); -} - -/** - * l_string_unwrap: - * @string: growable string object - * - * Free the growable string object and return the internal string data. - * The caller is responsible for freeing the string data using l_free(), - * and the string object is no longer usable. - * - * Returns: @string's internal buffer - **/ -LIB_EXPORT char *l_string_unwrap(struct l_string *string) -{ - char *result; - - if (unlikely(!string)) - return NULL; - - result = string->str; - - l_free(string); - - return result; -} - -/** - * l_string_append: - * @dest: growable string object - * @src: C-style string to copy - * - * Appends the contents of @src to @dest. The internal buffer of @dest is - * grown if necessary. - * - * Returns: @dest - **/ -LIB_EXPORT struct l_string *l_string_append(struct l_string *dest, - const char *src) -{ - size_t size; - - if (unlikely(!dest || !src)) - return NULL; - - size = strlen(src); - - grow_string(dest, size); - - memcpy(dest->str + dest->len, src, size); - dest->len += size; - dest->str[dest->len] = '\0'; - - return dest; -} - -/** - * l_string_append_c: - * @dest: growable string object - * @c: Character - * - * Appends character given by @c to @dest. The internal buffer of @dest is - * grown if necessary. - * - * Returns: @dest - **/ -LIB_EXPORT struct l_string *l_string_append_c(struct l_string *dest, - const char c) -{ - if (unlikely(!dest)) - return NULL; - - grow_string(dest, 1); - dest->str[dest->len++] = c; - dest->str[dest->len] = '\0'; - - return dest; -} - -/** - * l_string_append_fixed: - * @dest: growable string object - * @src: Character array to copy from - * @max: Maximum number of characters to copy - * - * Appends the contents of a fixed size string array @src to @dest. - * The internal buffer of @dest is grown if necessary. Up to a maximum of - * @max characters are copied. If a null is encountered in the first @max - * characters, the string is copied only up to the NULL character. - * - * Returns: @dest - **/ -LIB_EXPORT struct l_string *l_string_append_fixed(struct l_string *dest, - const char *src, - size_t max) -{ - const char *nul; - - if (unlikely(!dest || !src || !max)) - return NULL; - - nul = memchr(src, 0, max); - if (nul) - max = nul - src; - - grow_string(dest, max); - - memcpy(dest->str + dest->len, src, max); - dest->len += max; - dest->str[dest->len] = '\0'; - - return dest; -} - -/** - * l_string_append_vprintf: - * @dest: growable string object - * @format: the string format. See the sprintf() documentation - * @args: the parameters to insert - * - * Appends a formatted string to the growable string buffer. This function - * is equivalent to l_string_append_printf except that the arguments are - * passed as a va_list. - **/ -LIB_EXPORT void l_string_append_vprintf(struct l_string *dest, - const char *format, va_list args) -{ - size_t len; - size_t have_space; - va_list args_copy; - - if (unlikely(!dest)) - return; - -#if __STDC_VERSION__ > 199409L - va_copy(args_copy, args); -#else - __va_copy(args_copy, args); -#endif - - have_space = dest->max - dest->len; - len = vsnprintf(dest->str + dest->len, have_space, format, args); - - if (len >= have_space) { - grow_string(dest, len); - len = vsprintf(dest->str + dest->len, format, args_copy); - } - - dest->len += len; - - va_end(args_copy); -} - -/** - * l_string_append_printf: - * @dest: growable string object - * @format: the string format. See the sprintf() documentation - * @...: the parameters to insert - * - * Appends a formatted string to the growable string buffer, growing it as - * necessary. - **/ -LIB_EXPORT void l_string_append_printf(struct l_string *dest, - const char *format, ...) -{ - va_list args; - - if (unlikely(!dest)) - return; - - va_start(args, format); - l_string_append_vprintf(dest, format, args); - va_end(args); -} - -/** - * l_string_length: - * @string: growable string object - * - * Returns: bytes used in the string. - **/ -LIB_EXPORT unsigned int l_string_length(struct l_string *string) -{ - if (unlikely(!string)) - return 0; - - return string->len; -} - -LIB_EXPORT struct l_string *l_string_truncate(struct l_string *string, - size_t new_size) -{ - if (unlikely(!string)) - return NULL; - - if (new_size >= string->len) - return string; - - string->len = new_size; - string->str[new_size] = '\0'; - - return string; -} - -struct arg { - size_t max_len; - size_t cur_len; - char *chars; -}; - -static inline void arg_init(struct arg *arg) -{ - arg->max_len = 0; - arg->cur_len = 0; - arg->chars = NULL; -} - -static void arg_putchar(struct arg *arg, char ch) -{ - if (arg->cur_len == arg->max_len) { - arg->max_len += 32; /* Grow by at least 32 bytes */ - arg->chars = l_realloc(arg->chars, 1 + arg->max_len); - } - - arg->chars[arg->cur_len++] = ch; - arg->chars[arg->cur_len] = '\0'; -} - -static void arg_putmem(struct arg *arg, const void *mem, size_t len) -{ - if (len == 0) - return; - - if (arg->cur_len + len > arg->max_len) { - size_t growby = len * 2; - - if (growby < 32) - growby = 32; - - arg->max_len += growby; - arg->chars = l_realloc(arg->chars, 1 + arg->max_len); - } - - memcpy(arg->chars + arg->cur_len, mem, len); - arg->cur_len += len; - arg->chars[arg->cur_len] = '\0'; -} - -static bool parse_backslash(struct arg *arg, const char *args, size_t *pos) -{ - /* We're at the backslash, not within double quotes */ - char c = args[*pos + 1]; - - switch (c) { - case 0: - return false; - case '\n': - break; - default: - arg_putchar(arg, c); - break; - } - - *pos += 1; - return true; -} - -static bool parse_quoted_backslash(struct arg *arg, - const char *args, size_t *pos) -{ - /* We're at the backslash, within double quotes */ - char c = args[*pos + 1]; - - switch (c) { - case 0: - return false; - case '\n': - break; - case '"': - case '\\': - arg_putchar(arg, c); - break; - default: - arg_putchar(arg, '\\'); - arg_putchar(arg, c); - break; - } - - *pos += 1; - return true; -} - -static bool parse_single_quote(struct arg *arg, const char *args, size_t *pos) -{ - /* We're just past the single quote */ - size_t start = *pos; - - for (; args[*pos]; *pos += 1) { - if (args[*pos] != '\'') - continue; - - arg_putmem(arg, args + start, *pos - start); - return true; - } - - /* Unterminated ' */ - return false; -} - -static bool parse_double_quote(struct arg *arg, const char *args, size_t *pos) -{ - /* We're just past the double quote */ - for (; args[*pos]; *pos += 1) { - char c = args[*pos]; - - switch (c) { - case '"': - return true; - case '\\': - if (!parse_quoted_backslash(arg, args, pos)) - return false; - - break; - default: - arg_putchar(arg, c); - break; - } - } - - /* Unterminated */ - return false; -} - -static void add_arg(char ***args, char *arg, int *n_args) -{ - *args = l_realloc(*args, sizeof(char *) * (2 + *n_args)); - (*args)[*n_args] = arg; - (*args)[*n_args + 1] = NULL; - - *n_args += 1; -} - -LIB_EXPORT char **l_parse_args(const char *args, int *out_n_args) -{ - size_t i; - struct arg arg; - char **ret = l_realloc(NULL, sizeof(char *)); - int n_args = 0; - - ret[0] = NULL; - arg_init(&arg); - - for (i = 0; args[i]; i++) { - switch (args[i]) { - case '\\': - if (!parse_backslash(&arg, args, &i)) - goto error; - break; - case '"': - i += 1; - if (!parse_double_quote(&arg, args, &i)) - goto error; - - /* Add an empty string */ - if (!arg.cur_len) - add_arg(&ret, l_strdup(""), &n_args); - - break; - case '\'': - i += 1; - if (!parse_single_quote(&arg, args, &i)) - goto error; - - /* Add an empty string */ - if (!arg.cur_len) - add_arg(&ret, l_strdup(""), &n_args); - - break; - default: - if (!strchr(" \t", args[i])) { - if (args[i] == '\n') - goto error; - - arg_putchar(&arg, args[i]); - continue; - } - - if (arg.cur_len) - add_arg(&ret, arg.chars, &n_args); - - arg_init(&arg); - break; - } - } - - if (arg.cur_len) - add_arg(&ret, arg.chars, &n_args); - - if (out_n_args) - *out_n_args = n_args; - - return ret; - -error: - l_free(arg.chars); - l_strfreev(ret); - return NULL; -} diff --git a/ell/string.h b/ell/string.h deleted file mode 100644 index c1948ec..0000000 --- a/ell/string.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_STRING_H -#define __ELL_STRING_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_string; - -struct l_string *l_string_new(size_t initial_length); -void l_string_free(struct l_string *string); -char *l_string_unwrap(struct l_string *string); - -struct l_string *l_string_append(struct l_string *dest, const char *src); -struct l_string *l_string_append_c(struct l_string *dest, const char c); -struct l_string *l_string_append_fixed(struct l_string *dest, const char *src, - size_t max); - -void l_string_append_vprintf(struct l_string *dest, - const char *format, va_list args); -void l_string_append_printf(struct l_string *dest, const char *format, ...) - __attribute__((format(printf, 2, 3))); - -struct l_string *l_string_truncate(struct l_string *string, size_t new_size); - -unsigned int l_string_length(struct l_string *string); - -char **l_parse_args(const char *args, int *out_n_args); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_STRING_H */ diff --git a/ell/strv.c b/ell/strv.c deleted file mode 100644 index 484850b..0000000 --- a/ell/strv.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include - -#include "util.h" -#include "strv.h" -#include "private.h" - -/** - * SECTION:strv - * @short_description: String array functions - * - * String array functions - */ - -/** - * l_strfreev: - * @strlist: String list to free - * - * Frees a list of strings - **/ -LIB_EXPORT void l_strfreev(char **strlist) -{ - l_strv_free(strlist); -} - -/** - * l_strsplit: - * @str: String to split - * @sep: The delimiter character - * - * Splits a string into pieces which do not contain the delimiter character. - * As a special case, an empty string is returned as an empty array, e.g. - * an array with just the NULL element. - * - * Note that this function only works with ASCII delimiters. - * - * Returns: A newly allocated %NULL terminated string array. This array - * should be freed using l_strfreev(). - **/ -LIB_EXPORT char **l_strsplit(const char *str, const char sep) -{ - int len; - int i; - const char *p; - char **ret; - - if (unlikely(!str)) - return NULL; - - if (str[0] == '\0') - return l_new(char *, 1); - - for (p = str, len = 1; *p; p++) - if (*p == sep) - len += 1; - - ret = l_new(char *, len + 1); - - i = 0; - p = str; - len = 0; - - while (p[len]) { - if (p[len] != sep) { - len += 1; - continue; - } - - ret[i++] = l_strndup(p, len); - p += len + 1; - len = 0; - } - - ret[i++] = l_strndup(p, len); - - return ret; -} - -/** - * l_strsplit_set: - * @str: String to split - * @separators: A set of delimiters - * - * Splits a string into pieces which do not contain the delimiter characters - * that can be found in @separators. - * As a special case, an empty string is returned as an empty array, e.g. - * an array with just the NULL element. - * - * Note that this function only works with ASCII delimiters. - * - * Returns: A newly allocated %NULL terminated string array. This array - * should be freed using l_strfreev(). - **/ -LIB_EXPORT char **l_strsplit_set(const char *str, const char *separators) -{ - int len; - int i; - const char *p; - char **ret; - bool sep_table[256]; - - if (unlikely(!str)) - return NULL; - - if (str[0] == '\0') - return l_new(char *, 1); - - memset(sep_table, 0, sizeof(sep_table)); - - for (p = separators; *p; p++) - sep_table[(unsigned char) *p] = true; - - for (p = str, len = 1; *p; p++) - if (sep_table[(unsigned char) *p] == true) - len += 1; - - ret = l_new(char *, len + 1); - - i = 0; - p = str; - len = 0; - - while (p[len]) { - if (sep_table[(unsigned char) p[len]] != true) { - len += 1; - continue; - } - - ret[i++] = l_strndup(p, len); - p += len + 1; - len = 0; - } - - ret[i++] = l_strndup(p, len); - - return ret; -} - -/** - * l_strjoinv: - * @str_array: a %NULL terminated array of strings to join - * @delim: Delimiting character - * - * Joins strings contanied in the @str_array into one long string delimited - * by @delim. - * - * Returns: A newly allocated string that should be freed using l_free() - */ -LIB_EXPORT char *l_strjoinv(char **str_array, const char delim) -{ - size_t len = 0; - unsigned int i; - char *ret; - char *p; - - if (unlikely(!str_array)) - return NULL; - - if (!str_array[0]) - return l_strdup(""); - - for (i = 0; str_array[i]; i++) - len += strlen(str_array[i]); - - len += 1 + i - 1; - - ret = l_malloc(len); - - p = stpcpy(ret, str_array[0]); - - for (i = 1; str_array[i]; i++) { - *p++ = delim; - p = stpcpy(p, str_array[i]); - } - - return ret; -} - -/** - * l_strv_new: - * - * Returns: new emptry string array - **/ -LIB_EXPORT char **l_strv_new(void) -{ - return l_new(char *, 1); -} - -/** - * l_strv_free: - * @str_array: a %NULL terminated array of strings - * - * Frees strings in @str_array and @str_array itself - **/ -LIB_EXPORT void l_strv_free(char **str_array) -{ - if (likely(str_array)) { - int i; - - for (i = 0; str_array[i]; i++) - l_free(str_array[i]); - - l_free(str_array); - } -} - -/** - * l_strv_length: - * @str_array: a %NULL terminated array of strings - * - * Returns: the number of strings in @str_array - */ -LIB_EXPORT unsigned int l_strv_length(char **str_array) -{ - unsigned int i = 0; - - if (unlikely(!str_array)) - return 0; - - while (str_array[i]) - i += 1; - - return i; -} - -/** - * l_strv_contains: - * @str_array: a %NULL terminated array of strings - * @item: An item to search for, must be not %NULL - * - * Returns: #true if @str_array contains item - */ -LIB_EXPORT bool l_strv_contains(char **str_array, const char *item) -{ - unsigned int i = 0; - - if (unlikely(!str_array || !item)) - return false; - - while (str_array[i]) { - if (!strcmp(str_array[i], item)) - return true; - - i += 1; - } - - return false; -} - -/** - * l_strv_append: - * @str_array: a %NULL terminated array of strings or %NULL - * @str: A string to be appened at the end of @str_array - * - * Returns: New %NULL terminated array of strings with @str added - */ -LIB_EXPORT char **l_strv_append(char **str_array, const char *str) -{ - char **ret; - unsigned int i, len; - - if (unlikely(!str)) - return str_array; - - len = l_strv_length(str_array); - ret = l_new(char *, len + 2); - - for (i = 0; i < len; i++) - ret[i] = str_array[i]; - - ret[i] = l_strdup(str); - - l_free(str_array); - - return ret; -} - -LIB_EXPORT char **l_strv_append_printf(char **str_array, - const char *format, ...) -{ - va_list args; - char **ret; - - va_start(args, format); - ret = l_strv_append_vprintf(str_array, format, args); - va_end(args); - - return ret; -} - -LIB_EXPORT char **l_strv_append_vprintf(char **str_array, - const char *format, va_list args) -{ - char **ret; - unsigned int i, len; - - if (unlikely(!format)) - return str_array; - - len = l_strv_length(str_array); - ret = l_new(char *, len + 2); - - for (i = 0; i < len; i++) - ret[i] = str_array[i]; - - ret[i] = l_strdup_vprintf(format, args); - - l_free(str_array); - - return ret; -} - -/** - * l_strv_copy: - * @str_array: a %NULL terminated array of strings or %NULL - * - * Returns: An independent copy of @str_array. - */ -LIB_EXPORT char **l_strv_copy(char **str_array) -{ - int i, len; - char **copy; - - if (unlikely(!str_array)) - return NULL; - - for (len = 0; str_array[len]; len++); - - copy = l_malloc(sizeof(char *) * (len + 1)); - - for (i = len; i >= 0; i--) - copy[i] = l_strdup(str_array[i]); - - return copy; -} diff --git a/ell/strv.h b/ell/strv.h deleted file mode 100644 index b0ec17c..0000000 --- a/ell/strv.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_STRV_H -#define __ELL_STRV_H - -#ifdef __cplusplus -extern "C" { -#endif - -void l_strfreev(char **strlist); -char **l_strsplit(const char *str, const char sep); -char **l_strsplit_set(const char *str, const char *separators); -char *l_strjoinv(char **str_array, const char delim); - -char **l_strv_new(void); -void l_strv_free(char **str_array); -unsigned int l_strv_length(char **str_array); -bool l_strv_contains(char **str_array, const char *item); -char **l_strv_append(char **str_array, const char *str); -char **l_strv_append_printf(char **str_array, const char *format, ...) - __attribute__((format(printf, 2, 3))); -char **l_strv_append_vprintf(char **str_array, const char *format, - va_list args); -char **l_strv_copy(char **str_array); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_STRV_H */ diff --git a/ell/test.c b/ell/test.c deleted file mode 100644 index cdae8df..0000000 --- a/ell/test.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "log.h" -#include "test.h" -#include "private.h" - -/** - * SECTION:test - * @short_description: Unit test framework - * - * Unit test framework - */ - -struct test { - const char *name; - l_test_func_t function; - const void *test_data; - struct test *next; -}; - -static struct test *test_head; -static struct test *test_tail; - -/** - * l_test_init: - * @argc: pointer to @argc parameter of main() function - * @argv: pointer to @argv parameter of main() function - * - * Initialize testing framework. - **/ -LIB_EXPORT void l_test_init(int *argc, char ***argv) -{ - test_head = NULL; - test_tail = NULL; - - l_log_set_stderr(); -} - -/** - * l_test_run: - * - * Run all configured tests. - * - * Returns: 0 on success - **/ -LIB_EXPORT int l_test_run(void) -{ - struct test *test = test_head; - - while (test) { - struct test *tmp = test; - - printf("TEST: %s\n", test->name); - - test->function(test->test_data); - - test = test->next; - - free(tmp); - } - - test_head = NULL; - test_tail = NULL; - - return 0; -} - -/** - * l_test_add: - * @name: test name - * @function: test function - * @test_data: test data - * - * Add new test. - **/ -LIB_EXPORT void l_test_add(const char *name, l_test_func_t function, - const void *test_data) -{ - struct test *test; - - if (unlikely(!name || !function)) - return; - - test = malloc(sizeof(struct test)); - if (!test) - return; - - memset(test, 0, sizeof(struct test)); - test->name = name; - test->function = function; - test->test_data = test_data; - test->next = NULL; - - if (test_tail) - test_tail->next = test; - - test_tail = test; - - if (!test_head) - test_head = test; -} diff --git a/ell/test.h b/ell/test.h deleted file mode 100644 index f81d438..0000000 --- a/ell/test.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_TEST_H -#define __ELL_TEST_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*l_test_func_t) (const void *test_data); - -void l_test_init(int *argc, char ***argv); -int l_test_run(void); - -void l_test_add(const char *name, l_test_func_t function, - const void *test_data); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_TEST_H */ diff --git a/ell/time.c b/ell/time.c deleted file mode 100644 index 6150d03..0000000 --- a/ell/time.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include - -#include "time.h" -#include "private.h" - -/** - * l_time_now: - * - * Get the running clocktime in microseconds - * - * Returns: Current clock time in microseconds - **/ -LIB_EXPORT uint64_t l_time_now(void) -{ - struct timespec now; - - clock_gettime(CLOCK_BOOTTIME, &now); - - return now.tv_sec * 1000000 + now.tv_nsec / 1000; -} - -/** - * l_time_after - * - * Returns: True if time a is after time b - **/ - -/** - * l_time_before - * - * Returns: True if time a is before time b - **/ - -/** - * l_time_offset - * - * @time: Start time to calculate offset - * @offset: Amount of time to add to 'time' - * - * Adds an offset to a time value. This checks for overflow, and if detected - * returns UINT64_MAX. - * - * Returns: A time value 'time' + 'offset'. Or UINT64_MAX if time + offset - * exceeds UINT64_MAX. - **/ diff --git a/ell/time.h b/ell/time.h deleted file mode 100644 index 6976280..0000000 --- a/ell/time.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_TIME_H -#define __ELL_TIME_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#define L_USEC_PER_SEC 1000000ULL -#define L_MSEC_PER_SEC 1000ULL -#define L_USEC_PER_MSEC 1000ULL -#define L_NSEC_PER_SEC 1000000000ULL -#define L_NSEC_PER_MSEC 1000000ULL -#define L_NSEC_PER_USEC 1000ULL -#define L_TIME_INVALID ((uint64_t) -1) - -uint64_t l_time_now(void); - -static inline bool l_time_after(uint64_t a, uint64_t b) -{ - return a > b; -} - -static inline bool l_time_before(uint64_t a, uint64_t b) -{ - return l_time_after(b, a); -} - -static inline uint64_t l_time_offset(uint64_t time, uint64_t offset) -{ - /* check overflow */ - if (offset > UINT64_MAX - time) - return UINT64_MAX; - - return time + offset; -} - -static inline uint64_t l_time_diff(uint64_t a, uint64_t b) -{ - return (a < b) ? b - a : a - b; -} - -static inline uint64_t l_time_to_secs(uint64_t time) -{ - return time / L_USEC_PER_SEC; -} - -static inline uint64_t l_time_to_msecs(uint64_t time) -{ - return time / L_USEC_PER_MSEC; -} - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_TIME_H */ diff --git a/ell/timeout.c b/ell/timeout.c deleted file mode 100644 index f461328..0000000 --- a/ell/timeout.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "timeout.h" -#include "private.h" - -/** - * SECTION:timeout - * @short_description: Timeout support - * - * Timeout support - */ - -/** - * l_timeout: - * - * Opague object representing the timeout. - */ -struct l_timeout { - int fd; - l_timeout_notify_cb_t callback; - l_timeout_destroy_cb_t destroy; - void *user_data; -}; - -static void timeout_destroy(void *user_data) -{ - struct l_timeout *timeout = user_data; - - close(timeout->fd); - timeout->fd = -1; - - if (timeout->destroy) - timeout->destroy(timeout->user_data); -} - -static void timeout_callback(int fd, uint32_t events, void *user_data) -{ - struct l_timeout *timeout = user_data; - uint64_t expired; - ssize_t result; - - result = read(timeout->fd, &expired, sizeof(expired)); - if (result != sizeof(expired)) - return; - - if (timeout->callback) - timeout->callback(timeout, timeout->user_data); -} - -static inline int timeout_set(int fd, unsigned int seconds, long nanoseconds) -{ - struct itimerspec itimer; - - memset(&itimer, 0, sizeof(itimer)); - itimer.it_interval.tv_sec = 0; - itimer.it_interval.tv_nsec = 0; - itimer.it_value.tv_sec = seconds; - itimer.it_value.tv_nsec = nanoseconds; - - return timerfd_settime(fd, 0, &itimer, NULL); -} - -static bool convert_ms(unsigned long milliseconds, unsigned int *seconds, - long *nanoseconds) -{ - unsigned long big_seconds = milliseconds / 1000; - - if (big_seconds > UINT_MAX) - return false; - - *seconds = big_seconds; - *nanoseconds = (milliseconds % 1000) * 1000000L; - - return true; -} - -/** - * timeout_create_with_nanoseconds: - * @seconds: number of seconds - * @nanoseconds: number of nanoseconds - * @callback: timeout callback function - * @user_data: user data provided to timeout callback function - * @destroy: destroy function for user data - * - * Create new timeout callback handling. - * - * The timeout will only fire once. The timeout handling needs to be rearmed - * with one of the l_timeout_modify functions to trigger again. - * - * Returns: a newly allocated #l_timeout object. On failure, the function - * returns NULL. - **/ -static struct l_timeout *timeout_create_with_nanoseconds(unsigned int seconds, - long nanoseconds, l_timeout_notify_cb_t callback, - void *user_data, l_timeout_destroy_cb_t destroy) -{ - struct l_timeout *timeout; - int err; - - if (unlikely(!callback)) - return NULL; - - timeout = l_new(struct l_timeout, 1); - - timeout->callback = callback; - timeout->destroy = destroy; - timeout->user_data = user_data; - - timeout->fd = timerfd_create(CLOCK_MONOTONIC, - TFD_NONBLOCK | TFD_CLOEXEC); - if (timeout->fd < 0) { - l_free(timeout); - return NULL; - } - - if (seconds > 0 || nanoseconds > 0) { - if (timeout_set(timeout->fd, seconds, nanoseconds) < 0) { - close(timeout->fd); - l_free(timeout); - return NULL; - } - } - - err = watch_add(timeout->fd, EPOLLIN | EPOLLONESHOT, timeout_callback, - timeout, timeout_destroy); - - if (err < 0) { - l_free(timeout); - return NULL; - } - - return timeout; -} - -/** - * l_timeout_create: - * @seconds: timeout in seconds - * @callback: timeout callback function - * @user_data: user data provided to timeout callback function - * @destroy: destroy function for user data - * - * Create new timeout callback handling. - * - * The timeout will only fire once. The timeout handling needs to be rearmed - * with one of the l_timeout_modify functions to trigger again. - * - * Returns: a newly allocated #l_timeout object. On failure, the function - * returns NULL. - **/ -LIB_EXPORT struct l_timeout *l_timeout_create(unsigned int seconds, - l_timeout_notify_cb_t callback, - void *user_data, l_timeout_destroy_cb_t destroy) -{ - return timeout_create_with_nanoseconds(seconds, 0, callback, - user_data, destroy); -} - -/** - * l_timeout_create_ms: - * @milliseconds: timeout in milliseconds - * @callback: timeout callback function - * @user_data: user data provided to timeout callback function - * @destroy: destroy function for user data - * - * Create new timeout callback handling. - * - * The timeout will only fire once. The timeout handling needs to be rearmed - * with one of the l_timeout_modify functions to trigger again. - * - * Returns: a newly allocated #l_timeout object. On failure, the function - * returns NULL. - **/ -LIB_EXPORT struct l_timeout *l_timeout_create_ms(unsigned long milliseconds, - l_timeout_notify_cb_t callback, - void *user_data, l_timeout_destroy_cb_t destroy) -{ - unsigned int seconds; - long nanoseconds; - - if (!convert_ms(milliseconds, &seconds, &nanoseconds)) - return NULL; - - return timeout_create_with_nanoseconds(seconds, nanoseconds, callback, - user_data, destroy); -} - -/** - * l_timeout_modify: - * @timeout: timeout object - * @seconds: timeout in seconds - * - * Modify an existing @timeout and rearm it. - **/ -LIB_EXPORT void l_timeout_modify(struct l_timeout *timeout, - unsigned int seconds) -{ - if (unlikely(!timeout)) - return; - - if (unlikely(timeout->fd < 0)) - return; - - if (seconds > 0) { - if (timeout_set(timeout->fd, seconds, 0) < 0) - return; - } - - watch_modify(timeout->fd, EPOLLIN | EPOLLONESHOT, true); -} - -/** - * l_timeout_modify_ms: - * @timeout: timeout object - * @milliseconds: number of milliseconds - * - * Modify an existing @timeout and rearm it. - **/ -LIB_EXPORT void l_timeout_modify_ms(struct l_timeout *timeout, - unsigned long milliseconds) -{ - if (unlikely(!timeout)) - return; - - if (unlikely(timeout->fd < 0)) - return; - - if (milliseconds > 0) { - unsigned int sec; - long nanosec; - - if (!convert_ms(milliseconds, &sec, &nanosec) || - timeout_set(timeout->fd, sec, nanosec) < 0) - return; - } - - watch_modify(timeout->fd, EPOLLIN | EPOLLONESHOT, true); -} - -/** - * l_timeout_remove: - * @timeout: timeout object - * - * Remove timeout handling. - **/ -LIB_EXPORT void l_timeout_remove(struct l_timeout *timeout) -{ - if (unlikely(!timeout)) - return; - - watch_remove(timeout->fd); - - l_free(timeout); -} - -/** - * l_timeout_set_callback: - * @timeout: timeout object - * @callback: The new callback - * @user_data: The new user_data - * @destroy: The new destroy function - * - * Sets the new notify callback for @timeout. If the old user_data object had - * a destroy function set, then that function will be called. - */ -LIB_EXPORT void l_timeout_set_callback(struct l_timeout *timeout, - l_timeout_notify_cb_t callback, - void *user_data, - l_timeout_destroy_cb_t destroy) -{ - if (unlikely(!timeout)) - return; - - if (timeout->destroy) - timeout->destroy(timeout->user_data); - - timeout->callback = callback; - timeout->user_data = user_data; - timeout->destroy = destroy; -} diff --git a/ell/timeout.h b/ell/timeout.h deleted file mode 100644 index 889a287..0000000 --- a/ell/timeout.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_TIMEOUT_H -#define __ELL_TIMEOUT_H - -#ifdef __cplusplus -extern "C" { -#endif - -struct l_timeout; - -typedef void (*l_timeout_notify_cb_t) (struct l_timeout *timeout, - void *user_data); -typedef void (*l_timeout_destroy_cb_t) (void *user_data); - -struct l_timeout *l_timeout_create(unsigned int seconds, - l_timeout_notify_cb_t callback, - void *user_data, l_timeout_destroy_cb_t destroy); -struct l_timeout *l_timeout_create_ms(unsigned long milliseconds, - l_timeout_notify_cb_t callback, - void *user_data, l_timeout_destroy_cb_t destroy); -void l_timeout_modify(struct l_timeout *timeout, - unsigned int seconds); -void l_timeout_modify_ms(struct l_timeout *timeout, - unsigned long milliseconds); -void l_timeout_remove(struct l_timeout *timeout); -void l_timeout_set_callback(struct l_timeout *timeout, - l_timeout_notify_cb_t callback, void *user_data, - l_timeout_destroy_cb_t destroy); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_TIMEOUT_H */ diff --git a/ell/tls-extensions.c b/ell/tls-extensions.c deleted file mode 100644 index 2e2d9da..0000000 --- a/ell/tls-extensions.c +++ /dev/null @@ -1,907 +0,0 @@ -/* - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "util.h" -#include "tls.h" -#include "cipher.h" -#include "checksum.h" -#include "cert.h" -#include "tls-private.h" - -/* RFC 7919, Section A.1 */ -static const uint8_t tls_ffdhe2048_prime[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, - 0xa2, 0xbb, 0x4a, 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, - 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, - 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9, - 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, - 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, - 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, - 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, - 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, - 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, - 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, - 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, - 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, - 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, - 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, - 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, - 0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, - 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, - 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, 0x8e, 0xf1, 0x83, - 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, - 0x88, 0x6b, 0x42, 0x38, 0x61, 0x28, 0x5c, 0x97, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, -}; - -/* RFC 7919, Section A.2 */ -static const uint8_t tls_ffdhe3072_prime[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, - 0xa2, 0xbb, 0x4a, 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, - 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, - 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9, - 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, - 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, - 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, - 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, - 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, - 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, - 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, - 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, - 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, - 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, - 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, - 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, - 0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, - 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, - 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, 0x8e, 0xf1, 0x83, - 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, - 0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, - 0x65, 0x19, 0x03, 0x5b, 0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, - 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, 0xc9, 0x07, 0x7a, 0xd9, 0x1d, 0x26, - 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, 0x86, 0xd9, 0x1c, - 0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, - 0xbc, 0x43, 0x79, 0x44, 0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, - 0x64, 0xf2, 0xe2, 0x1e, 0x71, 0xf5, 0x4b, 0xff, 0x5c, 0xae, 0x82, 0xab, - 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d, - 0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, 0xbf, 0x9a, 0x42, - 0xd5, 0xc4, 0x48, 0x4e, 0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, - 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c, 0x25, 0xe4, 0x1d, 0x2b, - 0x66, 0xc6, 0x2e, 0x37, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; - -/* RFC 7919, Section A.3 */ -static const uint8_t tls_ffdhe4096_prime[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, - 0xa2, 0xbb, 0x4a, 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, - 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, - 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9, - 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, - 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, - 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, - 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, - 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, - 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, - 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, - 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, - 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, - 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, - 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, - 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, - 0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, - 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, - 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, 0x8e, 0xf1, 0x83, - 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, - 0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, - 0x65, 0x19, 0x03, 0x5b, 0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, - 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, 0xc9, 0x07, 0x7a, 0xd9, 0x1d, 0x26, - 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, 0x86, 0xd9, 0x1c, - 0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, - 0xbc, 0x43, 0x79, 0x44, 0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, - 0x64, 0xf2, 0xe2, 0x1e, 0x71, 0xf5, 0x4b, 0xff, 0x5c, 0xae, 0x82, 0xab, - 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d, - 0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, 0xbf, 0x9a, 0x42, - 0xd5, 0xc4, 0x48, 0x4e, 0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, - 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c, 0x25, 0xe4, 0x1d, 0x2b, - 0x66, 0x9e, 0x1e, 0xf1, 0x6e, 0x6f, 0x52, 0xc3, 0x16, 0x4d, 0xf4, 0xfb, - 0x79, 0x30, 0xe9, 0xe4, 0xe5, 0x88, 0x57, 0xb6, 0xac, 0x7d, 0x5f, 0x42, - 0xd6, 0x9f, 0x6d, 0x18, 0x77, 0x63, 0xcf, 0x1d, 0x55, 0x03, 0x40, 0x04, - 0x87, 0xf5, 0x5b, 0xa5, 0x7e, 0x31, 0xcc, 0x7a, 0x71, 0x35, 0xc8, 0x86, - 0xef, 0xb4, 0x31, 0x8a, 0xed, 0x6a, 0x1e, 0x01, 0x2d, 0x9e, 0x68, 0x32, - 0xa9, 0x07, 0x60, 0x0a, 0x91, 0x81, 0x30, 0xc4, 0x6d, 0xc7, 0x78, 0xf9, - 0x71, 0xad, 0x00, 0x38, 0x09, 0x29, 0x99, 0xa3, 0x33, 0xcb, 0x8b, 0x7a, - 0x1a, 0x1d, 0xb9, 0x3d, 0x71, 0x40, 0x00, 0x3c, 0x2a, 0x4e, 0xce, 0xa9, - 0xf9, 0x8d, 0x0a, 0xcc, 0x0a, 0x82, 0x91, 0xcd, 0xce, 0xc9, 0x7d, 0xcf, - 0x8e, 0xc9, 0xb5, 0x5a, 0x7f, 0x88, 0xa4, 0x6b, 0x4d, 0xb5, 0xa8, 0x51, - 0xf4, 0x41, 0x82, 0xe1, 0xc6, 0x8a, 0x00, 0x7e, 0x5e, 0x65, 0x5f, 0x6a, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; - -/* RFC 7919, Section A.4 */ -static const uint8_t tls_ffdhe6144_prime[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, - 0xa2, 0xbb, 0x4a, 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, - 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, - 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9, - 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, - 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, - 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, - 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, - 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, - 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, - 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, - 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, - 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, - 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, - 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, - 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, - 0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, - 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, - 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, 0x8e, 0xf1, 0x83, - 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, - 0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, - 0x65, 0x19, 0x03, 0x5b, 0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, - 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, 0xc9, 0x07, 0x7a, 0xd9, 0x1d, 0x26, - 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, 0x86, 0xd9, 0x1c, - 0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, - 0xbc, 0x43, 0x79, 0x44, 0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, - 0x64, 0xf2, 0xe2, 0x1e, 0x71, 0xf5, 0x4b, 0xff, 0x5c, 0xae, 0x82, 0xab, - 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d, - 0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, 0xbf, 0x9a, 0x42, - 0xd5, 0xc4, 0x48, 0x4e, 0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, - 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c, 0x25, 0xe4, 0x1d, 0x2b, - 0x66, 0x9e, 0x1e, 0xf1, 0x6e, 0x6f, 0x52, 0xc3, 0x16, 0x4d, 0xf4, 0xfb, - 0x79, 0x30, 0xe9, 0xe4, 0xe5, 0x88, 0x57, 0xb6, 0xac, 0x7d, 0x5f, 0x42, - 0xd6, 0x9f, 0x6d, 0x18, 0x77, 0x63, 0xcf, 0x1d, 0x55, 0x03, 0x40, 0x04, - 0x87, 0xf5, 0x5b, 0xa5, 0x7e, 0x31, 0xcc, 0x7a, 0x71, 0x35, 0xc8, 0x86, - 0xef, 0xb4, 0x31, 0x8a, 0xed, 0x6a, 0x1e, 0x01, 0x2d, 0x9e, 0x68, 0x32, - 0xa9, 0x07, 0x60, 0x0a, 0x91, 0x81, 0x30, 0xc4, 0x6d, 0xc7, 0x78, 0xf9, - 0x71, 0xad, 0x00, 0x38, 0x09, 0x29, 0x99, 0xa3, 0x33, 0xcb, 0x8b, 0x7a, - 0x1a, 0x1d, 0xb9, 0x3d, 0x71, 0x40, 0x00, 0x3c, 0x2a, 0x4e, 0xce, 0xa9, - 0xf9, 0x8d, 0x0a, 0xcc, 0x0a, 0x82, 0x91, 0xcd, 0xce, 0xc9, 0x7d, 0xcf, - 0x8e, 0xc9, 0xb5, 0x5a, 0x7f, 0x88, 0xa4, 0x6b, 0x4d, 0xb5, 0xa8, 0x51, - 0xf4, 0x41, 0x82, 0xe1, 0xc6, 0x8a, 0x00, 0x7e, 0x5e, 0x0d, 0xd9, 0x02, - 0x0b, 0xfd, 0x64, 0xb6, 0x45, 0x03, 0x6c, 0x7a, 0x4e, 0x67, 0x7d, 0x2c, - 0x38, 0x53, 0x2a, 0x3a, 0x23, 0xba, 0x44, 0x42, 0xca, 0xf5, 0x3e, 0xa6, - 0x3b, 0xb4, 0x54, 0x32, 0x9b, 0x76, 0x24, 0xc8, 0x91, 0x7b, 0xdd, 0x64, - 0xb1, 0xc0, 0xfd, 0x4c, 0xb3, 0x8e, 0x8c, 0x33, 0x4c, 0x70, 0x1c, 0x3a, - 0xcd, 0xad, 0x06, 0x57, 0xfc, 0xcf, 0xec, 0x71, 0x9b, 0x1f, 0x5c, 0x3e, - 0x4e, 0x46, 0x04, 0x1f, 0x38, 0x81, 0x47, 0xfb, 0x4c, 0xfd, 0xb4, 0x77, - 0xa5, 0x24, 0x71, 0xf7, 0xa9, 0xa9, 0x69, 0x10, 0xb8, 0x55, 0x32, 0x2e, - 0xdb, 0x63, 0x40, 0xd8, 0xa0, 0x0e, 0xf0, 0x92, 0x35, 0x05, 0x11, 0xe3, - 0x0a, 0xbe, 0xc1, 0xff, 0xf9, 0xe3, 0xa2, 0x6e, 0x7f, 0xb2, 0x9f, 0x8c, - 0x18, 0x30, 0x23, 0xc3, 0x58, 0x7e, 0x38, 0xda, 0x00, 0x77, 0xd9, 0xb4, - 0x76, 0x3e, 0x4e, 0x4b, 0x94, 0xb2, 0xbb, 0xc1, 0x94, 0xc6, 0x65, 0x1e, - 0x77, 0xca, 0xf9, 0x92, 0xee, 0xaa, 0xc0, 0x23, 0x2a, 0x28, 0x1b, 0xf6, - 0xb3, 0xa7, 0x39, 0xc1, 0x22, 0x61, 0x16, 0x82, 0x0a, 0xe8, 0xdb, 0x58, - 0x47, 0xa6, 0x7c, 0xbe, 0xf9, 0xc9, 0x09, 0x1b, 0x46, 0x2d, 0x53, 0x8c, - 0xd7, 0x2b, 0x03, 0x74, 0x6a, 0xe7, 0x7f, 0x5e, 0x62, 0x29, 0x2c, 0x31, - 0x15, 0x62, 0xa8, 0x46, 0x50, 0x5d, 0xc8, 0x2d, 0xb8, 0x54, 0x33, 0x8a, - 0xe4, 0x9f, 0x52, 0x35, 0xc9, 0x5b, 0x91, 0x17, 0x8c, 0xcf, 0x2d, 0xd5, - 0xca, 0xce, 0xf4, 0x03, 0xec, 0x9d, 0x18, 0x10, 0xc6, 0x27, 0x2b, 0x04, - 0x5b, 0x3b, 0x71, 0xf9, 0xdc, 0x6b, 0x80, 0xd6, 0x3f, 0xdd, 0x4a, 0x8e, - 0x9a, 0xdb, 0x1e, 0x69, 0x62, 0xa6, 0x95, 0x26, 0xd4, 0x31, 0x61, 0xc1, - 0xa4, 0x1d, 0x57, 0x0d, 0x79, 0x38, 0xda, 0xd4, 0xa4, 0x0e, 0x32, 0x9c, - 0xd0, 0xe4, 0x0e, 0x65, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; - -/* RFC 7919, Section A.5 */ -static const uint8_t tls_ffdhe8192_prime[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, - 0xa2, 0xbb, 0x4a, 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, - 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, - 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9, - 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, - 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, - 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, - 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, - 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, - 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, - 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, - 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, - 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, - 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, - 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, - 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, - 0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, - 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, - 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, 0x8e, 0xf1, 0x83, - 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, - 0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, - 0x65, 0x19, 0x03, 0x5b, 0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, - 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, 0xc9, 0x07, 0x7a, 0xd9, 0x1d, 0x26, - 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, 0x86, 0xd9, 0x1c, - 0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, - 0xbc, 0x43, 0x79, 0x44, 0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, - 0x64, 0xf2, 0xe2, 0x1e, 0x71, 0xf5, 0x4b, 0xff, 0x5c, 0xae, 0x82, 0xab, - 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d, - 0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, 0xbf, 0x9a, 0x42, - 0xd5, 0xc4, 0x48, 0x4e, 0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, - 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c, 0x25, 0xe4, 0x1d, 0x2b, - 0x66, 0x9e, 0x1e, 0xf1, 0x6e, 0x6f, 0x52, 0xc3, 0x16, 0x4d, 0xf4, 0xfb, - 0x79, 0x30, 0xe9, 0xe4, 0xe5, 0x88, 0x57, 0xb6, 0xac, 0x7d, 0x5f, 0x42, - 0xd6, 0x9f, 0x6d, 0x18, 0x77, 0x63, 0xcf, 0x1d, 0x55, 0x03, 0x40, 0x04, - 0x87, 0xf5, 0x5b, 0xa5, 0x7e, 0x31, 0xcc, 0x7a, 0x71, 0x35, 0xc8, 0x86, - 0xef, 0xb4, 0x31, 0x8a, 0xed, 0x6a, 0x1e, 0x01, 0x2d, 0x9e, 0x68, 0x32, - 0xa9, 0x07, 0x60, 0x0a, 0x91, 0x81, 0x30, 0xc4, 0x6d, 0xc7, 0x78, 0xf9, - 0x71, 0xad, 0x00, 0x38, 0x09, 0x29, 0x99, 0xa3, 0x33, 0xcb, 0x8b, 0x7a, - 0x1a, 0x1d, 0xb9, 0x3d, 0x71, 0x40, 0x00, 0x3c, 0x2a, 0x4e, 0xce, 0xa9, - 0xf9, 0x8d, 0x0a, 0xcc, 0x0a, 0x82, 0x91, 0xcd, 0xce, 0xc9, 0x7d, 0xcf, - 0x8e, 0xc9, 0xb5, 0x5a, 0x7f, 0x88, 0xa4, 0x6b, 0x4d, 0xb5, 0xa8, 0x51, - 0xf4, 0x41, 0x82, 0xe1, 0xc6, 0x8a, 0x00, 0x7e, 0x5e, 0x0d, 0xd9, 0x02, - 0x0b, 0xfd, 0x64, 0xb6, 0x45, 0x03, 0x6c, 0x7a, 0x4e, 0x67, 0x7d, 0x2c, - 0x38, 0x53, 0x2a, 0x3a, 0x23, 0xba, 0x44, 0x42, 0xca, 0xf5, 0x3e, 0xa6, - 0x3b, 0xb4, 0x54, 0x32, 0x9b, 0x76, 0x24, 0xc8, 0x91, 0x7b, 0xdd, 0x64, - 0xb1, 0xc0, 0xfd, 0x4c, 0xb3, 0x8e, 0x8c, 0x33, 0x4c, 0x70, 0x1c, 0x3a, - 0xcd, 0xad, 0x06, 0x57, 0xfc, 0xcf, 0xec, 0x71, 0x9b, 0x1f, 0x5c, 0x3e, - 0x4e, 0x46, 0x04, 0x1f, 0x38, 0x81, 0x47, 0xfb, 0x4c, 0xfd, 0xb4, 0x77, - 0xa5, 0x24, 0x71, 0xf7, 0xa9, 0xa9, 0x69, 0x10, 0xb8, 0x55, 0x32, 0x2e, - 0xdb, 0x63, 0x40, 0xd8, 0xa0, 0x0e, 0xf0, 0x92, 0x35, 0x05, 0x11, 0xe3, - 0x0a, 0xbe, 0xc1, 0xff, 0xf9, 0xe3, 0xa2, 0x6e, 0x7f, 0xb2, 0x9f, 0x8c, - 0x18, 0x30, 0x23, 0xc3, 0x58, 0x7e, 0x38, 0xda, 0x00, 0x77, 0xd9, 0xb4, - 0x76, 0x3e, 0x4e, 0x4b, 0x94, 0xb2, 0xbb, 0xc1, 0x94, 0xc6, 0x65, 0x1e, - 0x77, 0xca, 0xf9, 0x92, 0xee, 0xaa, 0xc0, 0x23, 0x2a, 0x28, 0x1b, 0xf6, - 0xb3, 0xa7, 0x39, 0xc1, 0x22, 0x61, 0x16, 0x82, 0x0a, 0xe8, 0xdb, 0x58, - 0x47, 0xa6, 0x7c, 0xbe, 0xf9, 0xc9, 0x09, 0x1b, 0x46, 0x2d, 0x53, 0x8c, - 0xd7, 0x2b, 0x03, 0x74, 0x6a, 0xe7, 0x7f, 0x5e, 0x62, 0x29, 0x2c, 0x31, - 0x15, 0x62, 0xa8, 0x46, 0x50, 0x5d, 0xc8, 0x2d, 0xb8, 0x54, 0x33, 0x8a, - 0xe4, 0x9f, 0x52, 0x35, 0xc9, 0x5b, 0x91, 0x17, 0x8c, 0xcf, 0x2d, 0xd5, - 0xca, 0xce, 0xf4, 0x03, 0xec, 0x9d, 0x18, 0x10, 0xc6, 0x27, 0x2b, 0x04, - 0x5b, 0x3b, 0x71, 0xf9, 0xdc, 0x6b, 0x80, 0xd6, 0x3f, 0xdd, 0x4a, 0x8e, - 0x9a, 0xdb, 0x1e, 0x69, 0x62, 0xa6, 0x95, 0x26, 0xd4, 0x31, 0x61, 0xc1, - 0xa4, 0x1d, 0x57, 0x0d, 0x79, 0x38, 0xda, 0xd4, 0xa4, 0x0e, 0x32, 0x9c, - 0xcf, 0xf4, 0x6a, 0xaa, 0x36, 0xad, 0x00, 0x4c, 0xf6, 0x00, 0xc8, 0x38, - 0x1e, 0x42, 0x5a, 0x31, 0xd9, 0x51, 0xae, 0x64, 0xfd, 0xb2, 0x3f, 0xce, - 0xc9, 0x50, 0x9d, 0x43, 0x68, 0x7f, 0xeb, 0x69, 0xed, 0xd1, 0xcc, 0x5e, - 0x0b, 0x8c, 0xc3, 0xbd, 0xf6, 0x4b, 0x10, 0xef, 0x86, 0xb6, 0x31, 0x42, - 0xa3, 0xab, 0x88, 0x29, 0x55, 0x5b, 0x2f, 0x74, 0x7c, 0x93, 0x26, 0x65, - 0xcb, 0x2c, 0x0f, 0x1c, 0xc0, 0x1b, 0xd7, 0x02, 0x29, 0x38, 0x88, 0x39, - 0xd2, 0xaf, 0x05, 0xe4, 0x54, 0x50, 0x4a, 0xc7, 0x8b, 0x75, 0x82, 0x82, - 0x28, 0x46, 0xc0, 0xba, 0x35, 0xc3, 0x5f, 0x5c, 0x59, 0x16, 0x0c, 0xc0, - 0x46, 0xfd, 0x82, 0x51, 0x54, 0x1f, 0xc6, 0x8c, 0x9c, 0x86, 0xb0, 0x22, - 0xbb, 0x70, 0x99, 0x87, 0x6a, 0x46, 0x0e, 0x74, 0x51, 0xa8, 0xa9, 0x31, - 0x09, 0x70, 0x3f, 0xee, 0x1c, 0x21, 0x7e, 0x6c, 0x38, 0x26, 0xe5, 0x2c, - 0x51, 0xaa, 0x69, 0x1e, 0x0e, 0x42, 0x3c, 0xfc, 0x99, 0xe9, 0xe3, 0x16, - 0x50, 0xc1, 0x21, 0x7b, 0x62, 0x48, 0x16, 0xcd, 0xad, 0x9a, 0x95, 0xf9, - 0xd5, 0xb8, 0x01, 0x94, 0x88, 0xd9, 0xc0, 0xa0, 0xa1, 0xfe, 0x30, 0x75, - 0xa5, 0x77, 0xe2, 0x31, 0x83, 0xf8, 0x1d, 0x4a, 0x3f, 0x2f, 0xa4, 0x57, - 0x1e, 0xfc, 0x8c, 0xe0, 0xba, 0x8a, 0x4f, 0xe8, 0xb6, 0x85, 0x5d, 0xfe, - 0x72, 0xb0, 0xa6, 0x6e, 0xde, 0xd2, 0xfb, 0xab, 0xfb, 0xe5, 0x8a, 0x30, - 0xfa, 0xfa, 0xbe, 0x1c, 0x5d, 0x71, 0xa8, 0x7e, 0x2f, 0x74, 0x1e, 0xf8, - 0xc1, 0xfe, 0x86, 0xfe, 0xa6, 0xbb, 0xfd, 0xe5, 0x30, 0x67, 0x7f, 0x0d, - 0x97, 0xd1, 0x1d, 0x49, 0xf7, 0xa8, 0x44, 0x3d, 0x08, 0x22, 0xe5, 0x06, - 0xa9, 0xf4, 0x61, 0x4e, 0x01, 0x1e, 0x2a, 0x94, 0x83, 0x8f, 0xf8, 0x8c, - 0xd6, 0x8c, 0x8b, 0xb7, 0xc5, 0xc6, 0x42, 0x4c, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, -}; - -/* RFC 3526, Section 3 */ -static const uint8_t tls_dh14_prime[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, - 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, - 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, - 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, - 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, - 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, - 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4, 0x4c, 0x42, 0xe9, - 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, - 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, - 0x7c, 0x4b, 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, - 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05, 0x98, 0xda, 0x48, 0x36, - 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f, - 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, - 0x20, 0x85, 0x52, 0xbb, 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, - 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04, 0xf1, 0x74, 0x6c, 0x08, - 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b, - 0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, - 0xec, 0x07, 0xa2, 0x8f, 0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, - 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7c, - 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10, - 0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xac, 0xaa, 0x68, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, -}; - -static const struct tls_named_group tls_group_pref[] = { - { "secp256r1", 23, TLS_GROUP_TYPE_EC }, - { "secp384r1", 24, TLS_GROUP_TYPE_EC }, - { - "ffdhe2048", 256, TLS_GROUP_TYPE_FF, - .ff = { - .prime = tls_ffdhe2048_prime, - .prime_len = sizeof(tls_ffdhe2048_prime), - .generator = 2, - }, - }, - { - "ffdhe3072", 257, TLS_GROUP_TYPE_FF, - .ff = { - .prime = tls_ffdhe3072_prime, - .prime_len = sizeof(tls_ffdhe3072_prime), - .generator = 2, - }, - }, - { - "ffdhe4096", 258, TLS_GROUP_TYPE_FF, - .ff = { - .prime = tls_ffdhe4096_prime, - .prime_len = sizeof(tls_ffdhe4096_prime), - .generator = 2, - }, - }, - { - "ffdhe6144", 259, TLS_GROUP_TYPE_FF, - .ff = { - .prime = tls_ffdhe6144_prime, - .prime_len = sizeof(tls_ffdhe6144_prime), - .generator = 2, - }, - }, - { - "ffdhe8192", 260, TLS_GROUP_TYPE_FF, - .ff = { - .prime = tls_ffdhe8192_prime, - .prime_len = sizeof(tls_ffdhe8192_prime), - .generator = 2, - }, - }, -}; - -/* - * For now hardcode a default group for non-RFC7919 clients - same group - * as some other TLS servers use, which is actually a downside because the - * more common the group parameters are the less secure they are assumed - * to be, but it is also a test that the group is sufficiently good. - * - * Eventually we need to make this configurable so that a unique - * likely-prime number generated by either 'openssl dhparam' or - * 'ssh-keygen -G' can be set, or parse /etc/ssh/moduli to select - * a random pre-generated FFDH group each time. - */ -static const struct tls_named_group tls_default_ffdh_group = { - "RFC3526/Oakley Group 14", 0, TLS_GROUP_TYPE_FF, - .ff = { - .prime = tls_dh14_prime, - .prime_len = sizeof(tls_dh14_prime), - .generator = 2, - }, -}; - -/* RFC 8422, Section 5.1 + RFC 7919 */ -static ssize_t tls_elliptic_curves_client_write(struct l_tls *tls, - uint8_t *buf, size_t len) -{ - uint8_t *ptr = buf; - unsigned int i; - - if (len < 2 + L_ARRAY_SIZE(tls_group_pref) * 2) - return -ENOMEM; - - l_put_be16(L_ARRAY_SIZE(tls_group_pref) * 2, ptr); - ptr += 2; - - for (i = 0; i < L_ARRAY_SIZE(tls_group_pref); i++) { - l_put_be16(tls_group_pref[i].id, ptr); - ptr += 2; - } - - return ptr - buf; -} - -static bool tls_elliptic_curves_client_handle(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - bool ffdh_offered = false; - - if (len < 2) - return false; - - if (l_get_be16(buf) != len - 2 || (len & 1)) - return false; - - buf += 2; - len -= 2; - - /* - * We select one group for DH and one group for ECDH and we'll - * let the cipher suite selection logic decide which one is actually - * used. It will take into account the client's cipher suite - * preference but it could just as well look at the strengths of - * the groups chosen. This is not done for simplicity but RFC 7919 - * suggests the Supported Groups should actually overrule the - * cipher suite preference list in case of a conflict: - * "A server that encounters such a contradiction when selecting - * between an ECDHE or FFDHE key exchange mechanism while trying - * to respect client preferences SHOULD give priority to the - * Supported Groups extension (...) but MAY resolve the - * contradiction any way it sees fit." - * - * Not implemented: "If a non-anonymous FFDHE cipher suite is - * selected and the TLS client has used this extension to offer - * an FFDHE group of comparable or greater strength than the server's - * public key, the server SHOULD select an FFDHE group at least - * as strong as the server's public key." - */ - - while (len) { - unsigned int i; - uint16_t id; - const struct tls_named_group *group = NULL; - - id = l_get_be16(buf); - buf += 2; - len -= 2; - - if (id >> 8 == 1) /* RFC 7919 ids */ - ffdh_offered = true; - - for (i = 0; i < L_ARRAY_SIZE(tls_group_pref); i++) - if (tls_group_pref[i].id == id) { - group = &tls_group_pref[i]; - break; - } - - if (!group) - continue; - - switch (group->type) { - case TLS_GROUP_TYPE_EC: - if (!tls->negotiated_curve) - tls->negotiated_curve = group; - - break; - case TLS_GROUP_TYPE_FF: - if (!tls->negotiated_ff_group) - tls->negotiated_ff_group = group; - - break; - } - } - - /* - * Note we need to treat DH slightly differently from ECDH groups - * here because the extension is defined in RFC 8422 and if the - * client offers no elliptic curves we can't use ECDH at all: - * "If a server (...) is unable to complete the ECC handshake while - * restricting itself to the enumerated curves (...), it MUST NOT - * negotiate the use of an ECC cipher suite. Depending on what - * other cipher suites are proposed by the client and supported by - * the server, this may result in a fatal handshake failure alert - * due to the lack of common cipher suites." - * - * On the other hand if the client offers no FFDH groups we can - * only assume the client is okay with us picking a group. Note - * the "includes any FFDHE group" part in RFC 7919 Section 4: - * "If a compatible TLS server receives a Supported Groups - * extension from a client that includes any FFDHE group (i.e., - * any codepoint between 256 and 511, inclusive, even if unknown - * to the server), and if none of the client-proposed FFDHE groups - * are known and acceptable to the server, then the server MUST - * NOT select an FFDHE cipher suite." - */ - - if (tls->negotiated_curve) - TLS_DEBUG("Negotiated %s", tls->negotiated_curve->name); - else - TLS_DEBUG("non-fatal: No common supported elliptic curves " - "for ECDHE"); - - if (tls->negotiated_ff_group) - TLS_DEBUG("Negotiated %s", tls->negotiated_ff_group->name); - else if (ffdh_offered) - TLS_DEBUG("non-fatal: No common supported finite-field groups " - "for DHE"); - else - tls->negotiated_ff_group = &tls_default_ffdh_group; - - return true; -} - -static bool tls_elliptic_curves_client_absent(struct l_tls *tls) -{ - unsigned int i; - - for (i = 0; i < L_ARRAY_SIZE(tls_group_pref); i++) - if (tls_group_pref[i].type == TLS_GROUP_TYPE_EC) { - tls->negotiated_curve = &tls_group_pref[i]; - break; - } - - tls->negotiated_ff_group = &tls_default_ffdh_group; - - return true; -} - -static bool tls_ec_point_formats_client_handle(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - if (len < 2) - return false; - - if (buf[0] != len - 1) - return false; - - if (!memchr(buf + 1, 0, len - 1)) { - TLS_DEBUG("Uncompressed point format missing"); - return false; - } - - return true; -} - -/* - * For compatibility with clients respond to a valid Client Hello Supported - * Point Formats extension with the hardcoded confirmation that we do - * support the single valid point format. As a client we never send this - * extension so we never have to handle a server response to it either. - */ -static ssize_t tls_ec_point_formats_server_write(struct l_tls *tls, - uint8_t *buf, size_t len) -{ - if (len < 2) - return -ENOMEM; - - buf[0] = 0x01; /* ec_point_format_list length */ - buf[1] = 0x00; /* uncompressed */ - return 2; -} - -/* - * This is used to append the list of signature algorithm and hash type - * combinations we support to the Signature Algorithms client hello - * extension (on the client) and the Certificate Request message (on the - * server). In both cases we need to list the algorithms we support for - * two use cases: certificate chain verification and signing/verifying - * Server Key Exchange params (server->client) or Certificate Verify - * data (client->server). - * - * For the server side RFC 5462, Section 7.4.1.4.1 says: - * "If the client [...] is willing to use them for verifying - * messages sent by the server, i.e., server certificates and - * server key exchange [...] it MUST send the - * signature_algorithms extension, listing the algorithms it - * is willing to accept." - * - * As for the certificate chains we mostly rely on the kernel to do - * this so when we receive the list we do not currently verify the - * that the whole chain uses only algorithms from the list on either - * side (TODO). But we know that the chain verification in the kernel - * can use a superset of the hash algorithms l_checksum supports. - * For the Server Key Exchange and Certificate Verify signatures we - * use l_checksum but we need to map the TLS-specific hash IDs to - * enum l_checksum_type using the tls_handshake_hash_data list in - * signature->sign() and signature->verify(), so we use - * tls_handshake_hash_data as the definitive list of allowed hash - * algorithms. - * - * Our supported signature algorithms can work with any hash type so we - * basically have to send all possible combinations of the signature - * algorithm IDs from the supported cipher suites (except anonymous) - * with the hash algorithms we can use for signature verification, - * i.e. those in the tls_handshake_hash_data table. - */ -ssize_t tls_write_signature_algorithms(struct l_tls *tls, - uint8_t *buf, size_t len) -{ - uint8_t *ptr = buf; - unsigned int i, j; - struct tls_cipher_suite **suite; - uint8_t sig_alg_ids[16]; - uint8_t hash_ids[16]; - unsigned int sig_alg_cnt = 0; - unsigned int hash_cnt = 0; - - for (suite = tls->cipher_suite_pref_list; *suite; suite++) { - uint8_t id; - - if (!(*suite)->signature) - continue; - - id = (*suite)->signature->id; - - if (memchr(sig_alg_ids, id, sig_alg_cnt)) - continue; - - if (!tls_cipher_suite_is_compatible(tls, *suite, NULL)) - continue; - - if (sig_alg_cnt >= sizeof(sig_alg_ids)) - return -ENOMEM; - - sig_alg_ids[sig_alg_cnt++] = id; - } - - for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++) { - const struct tls_hash_algorithm *hash = - &tls_handshake_hash_data[i]; - bool supported; - - /* - * The hash types in the Signature Algorithms extension are - * all supported hashes but the ones in the Certificate - * Request (server->client) must be in the set for which we - * maintain handshake message hashes because that is going - * to be used in Certificate Verify. - */ - if (tls->server) - supported = !!tls->handshake_hash[i]; - else - supported = l_checksum_is_supported(hash->l_id, false); - - if (supported) - hash_ids[hash_cnt++] = hash->tls_id; - } - - if (len < 2 + sig_alg_cnt * hash_cnt * 2) - return -ENOMEM; - - l_put_be16(sig_alg_cnt * hash_cnt * 2, ptr); - ptr += 2; - - for (i = 0; i < sig_alg_cnt; i++) - for (j = 0; j < hash_cnt; j++) { - *ptr++ = hash_ids[j]; - *ptr++ = sig_alg_ids[i]; - } - - return ptr - buf; -} - -ssize_t tls_parse_signature_algorithms(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - const uint8_t *ptr = buf; - enum handshake_hash_type first_supported, hash; - const struct tls_hash_algorithm *preferred; - struct tls_cipher_suite **suite; - uint8_t sig_alg_ids[16]; - unsigned int sig_alg_cnt = 0; - - /* - * This only makes sense as a variable-length field, assume - * there's a typo in RFC5246 7.4.4 here. - */ - if (len < 4) - return -EINVAL; - - if (l_get_be16(ptr) > len - 2) - return -EINVAL; - - len = l_get_be16(ptr); - ptr += 2; - - if (len & 1) - return -EINVAL; - - for (suite = tls->cipher_suite_pref_list; *suite; suite++) { - uint8_t id; - - if (!(*suite)->signature) - continue; - - id = (*suite)->signature->id; - - if (memchr(sig_alg_ids, id, sig_alg_cnt)) - continue; - - if (!tls_cipher_suite_is_compatible(tls, *suite, NULL)) - continue; - - if (sig_alg_cnt >= sizeof(sig_alg_ids)) - return -ENOMEM; - - sig_alg_ids[sig_alg_cnt++] = id; - } - - /* - * In 1.2 we force our preference for SHA256/SHA384 (depending on - * cipher suite's PRF hmac) if it is supported by the peer because - * that must be supported anyway for the PRF and the Finished hash - * meaning that we only need to keep one hash instead of two. - * If not available fall back to the first common hash algorithm. - */ - first_supported = -1; - - if (tls->prf_hmac) - preferred = tls->prf_hmac; - else - preferred = &tls_handshake_hash_data[HANDSHAKE_HASH_SHA256]; - - while (len) { - uint8_t hash_id = *ptr++; - uint8_t sig_alg_id = *ptr++; - bool supported; - - len -= 2; - - /* Ignore hash types for signatures other than ours */ - if (tls->pending.cipher_suite && - (!tls->pending.cipher_suite->signature || - tls->pending.cipher_suite->signature->id != - sig_alg_id)) - continue; - else if (!tls->pending.cipher_suite && - !memchr(sig_alg_ids, sig_alg_id, sig_alg_cnt)) - continue; - - if (hash_id == preferred->tls_id) { - for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) - if (&tls_handshake_hash_data[hash] == preferred) - break; - break; - } - - if ((int) first_supported != -1) - continue; - - for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) - if (hash_id == tls_handshake_hash_data[hash].tls_id) - break; - - if (hash == __HANDSHAKE_HASH_COUNT) - continue; - - if (tls->server) - supported = l_checksum_is_supported( - tls_handshake_hash_data[hash].l_id, - false); - else - supported = !!tls->handshake_hash[hash]; - - if (supported) - first_supported = hash; - } - - if (len) - tls->signature_hash = hash; - else if ((int) first_supported != -1) - tls->signature_hash = first_supported; - else - return -ENOTSUP; - - return ptr + len - buf; -} - -/* RFC 5462, Section 7.4.1.4.1 */ -static ssize_t tls_signature_algorithms_client_write(struct l_tls *tls, - uint8_t *buf, size_t len) -{ - /* - * "Note: this extension is not meaningful for TLS versions - * prior to 1.2. Clients MUST NOT offer it if they are offering - * prior versions." - */ - if (tls->max_version < L_TLS_V12) - return -ENOMSG; - - return tls_write_signature_algorithms(tls, buf, len); -} - -static bool tls_signature_algorithms_client_handle(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - ssize_t ret; - - /* - * "However, even if clients do offer it, the rules specified in - * [TLSEXT] require servers to ignore extensions they do not - * understand." - */ - if (tls->max_version < L_TLS_V12) - return true; - - ret = tls_parse_signature_algorithms(tls, buf, len); - - if (ret == -ENOTSUP) - TLS_DEBUG("No common signature algorithms"); - - /* - * TODO: also check our certificate chain against the parsed - * signature algorithms. - */ - - return ret == (ssize_t) len; -} - -static bool tls_signature_algorithms_client_absent(struct l_tls *tls) -{ - /* - * "If the client does not send the signature_algorithms extension, - * the server MUST do the following: - * - [...] behave as if client had sent the value {sha1,rsa}. - * - [...] behave as if client had sent the value {sha1,dsa}. - * - [...] behave as if client had sent the value {sha1,ecdsa}. - */ - if (tls->max_version >= L_TLS_V12) - tls->signature_hash = HANDSHAKE_HASH_SHA1; - - return true; -} - -const struct tls_hello_extension tls_extensions[] = { - { - "Supported Groups", "elliptic_curves", 10, - tls_elliptic_curves_client_write, - tls_elliptic_curves_client_handle, - tls_elliptic_curves_client_absent, - NULL, NULL, NULL, - }, - { - "Supported Point Formats", "ec_point_formats", 11, - NULL, - tls_ec_point_formats_client_handle, - NULL, - tls_ec_point_formats_server_write, - NULL, NULL, - }, - { - "Signature Algorithms", "signature_algoritms", 13, - tls_signature_algorithms_client_write, - tls_signature_algorithms_client_handle, - tls_signature_algorithms_client_absent, - NULL, NULL, NULL, - }, - {} -}; - -const struct tls_named_group *tls_find_group(uint16_t id) -{ - unsigned int i; - - for (i = 0; i < L_ARRAY_SIZE(tls_group_pref); i++) - if (tls_group_pref[i].id == id) - return &tls_group_pref[i]; - - return NULL; -} - -const struct tls_named_group *tls_find_ff_group(const uint8_t *prime, - size_t prime_len, - const uint8_t *generator, - size_t generator_len) -{ - unsigned int i; - - if (generator_len != 1) - return NULL; - - for (i = 0; i < L_ARRAY_SIZE(tls_group_pref); i++) { - const struct tls_named_group *g = &tls_group_pref[i]; - - if (g->type != TLS_GROUP_TYPE_FF) - continue; - - if (g->ff.prime_len != prime_len || - memcmp(prime, g->ff.prime, prime_len)) - continue; - - if (g->ff.generator != *generator) - continue; - - return g; - } - - return NULL; -} diff --git a/ell/tls-private.h b/ell/tls-private.h deleted file mode 100644 index 908c622..0000000 --- a/ell/tls-private.h +++ /dev/null @@ -1,360 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#define TLS_MAX_VERSION L_TLS_V12 -#define TLS_MIN_VERSION L_TLS_V10 - -enum tls_cipher_type { - TLS_CIPHER_STREAM, - TLS_CIPHER_BLOCK, - TLS_CIPHER_AEAD, -}; - -struct tls_bulk_encryption_algorithm { - enum tls_cipher_type cipher_type; - union { - enum l_cipher_type l_id; - enum l_aead_cipher_type l_aead_id; - }; - size_t key_length; - size_t iv_length; - size_t fixed_iv_length; - size_t block_length; - size_t auth_tag_length; -}; - -struct tls_hash_algorithm { - uint8_t tls_id; - enum l_checksum_type l_id; - const char *name; -}; - -/* - * Support the minimum required set of handshake hash types for the - * Certificate Verify digital signature and the Finished PRF seed so we - * don't have to accumulate all of messages full contents until the - * Finished message. If we're sent a hash of a different type (in TLS 1.2+) - * and need to verify we'll give up. - * SHA1 and MD5 are explicitly required by versions < 1.2 and 1.2 requires - * that the Finished hash is the same as used for the PRF so we need to - * keep at least the hashes our supported cipher suites specify for the PRF. - */ -enum handshake_hash_type { - HANDSHAKE_HASH_SHA384, - HANDSHAKE_HASH_SHA256, - HANDSHAKE_HASH_MD5, - HANDSHAKE_HASH_SHA1, - __HANDSHAKE_HASH_COUNT, -}; -#define HANDSHAKE_HASH_MAX_SIZE 48 - -extern const struct tls_hash_algorithm tls_handshake_hash_data[]; - -typedef bool (*tls_get_hash_t)(struct l_tls *tls, - enum handshake_hash_type type, - const uint8_t *data, size_t data_len, - uint8_t *out, size_t *out_len); - -struct tls_signature_algorithm { - uint8_t id; - - bool (*validate_cert_key_type)(struct l_cert *cert); - - ssize_t (*sign)(struct l_tls *tls, uint8_t *out, size_t out_len, - tls_get_hash_t get_hash, - const uint8_t *data, size_t data_len); - bool (*verify)(struct l_tls *tls, const uint8_t *in, size_t in_len, - tls_get_hash_t get_hash, - const uint8_t *data, size_t data_len); -}; - -struct tls_key_exchange_algorithm { - bool need_ecc; - bool need_ffdh; - - bool (*send_server_key_exchange)(struct l_tls *tls); - void (*handle_server_key_exchange)(struct l_tls *tls, - const uint8_t *buf, size_t len); - - bool (*send_client_key_exchange)(struct l_tls *tls); - void (*handle_client_key_exchange)(struct l_tls *tls, - const uint8_t *buf, size_t len); - - void (*free_params)(struct l_tls *tls); -}; - -struct tls_mac_algorithm { - uint8_t id; - enum l_checksum_type hmac_type; - size_t mac_length; -}; - -struct tls_cipher_suite { - uint8_t id[2]; - const char *name; - int verify_data_length; - - struct tls_bulk_encryption_algorithm *encryption; - struct tls_signature_algorithm *signature; - struct tls_key_exchange_algorithm *key_xchg; - struct tls_mac_algorithm *mac; - enum l_checksum_type prf_hmac; -}; - -extern struct tls_cipher_suite *tls_cipher_suite_pref[]; - -struct tls_compression_method { - int id; - const char *name; -}; - -struct tls_hello_extension { - const char *name; - const char *short_name; - uint16_t id; - ssize_t (*client_write)(struct l_tls *tls, uint8_t *buf, size_t len); - /* Handle a Client Hello extension (on server), can't be NULL */ - bool (*client_handle)(struct l_tls *tls, - const uint8_t *buf, size_t len); - /* Handle a Client Hello extension's absence (on server) */ - bool (*client_handle_absent)(struct l_tls *tls); - ssize_t (*server_write)(struct l_tls *tls, uint8_t *buf, size_t len); - /* Handle a Server Hello extension (on client) */ - bool (*server_handle)(struct l_tls *tls, - const uint8_t *buf, size_t len); - /* Handle a Server Hello extension's absence (on client) */ - bool (*server_handle_absent)(struct l_tls *tls); -}; - -extern const struct tls_hello_extension tls_extensions[]; - -struct tls_named_group { - const char *name; - uint16_t id; - enum { - TLS_GROUP_TYPE_EC, - TLS_GROUP_TYPE_FF, - } type; - union { - struct { - const uint8_t *prime; - size_t prime_len; - unsigned int generator; - } ff; - }; -}; - -enum tls_handshake_state { - TLS_HANDSHAKE_WAIT_START, - TLS_HANDSHAKE_WAIT_HELLO, - TLS_HANDSHAKE_WAIT_CERTIFICATE, - TLS_HANDSHAKE_WAIT_KEY_EXCHANGE, - TLS_HANDSHAKE_WAIT_HELLO_DONE, - TLS_HANDSHAKE_WAIT_CERTIFICATE_VERIFY, - TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC, - TLS_HANDSHAKE_WAIT_FINISHED, - TLS_HANDSHAKE_DONE, -}; - -enum tls_content_type { - TLS_CT_CHANGE_CIPHER_SPEC = 20, - TLS_CT_ALERT = 21, - TLS_CT_HANDSHAKE = 22, - TLS_CT_APPLICATION_DATA = 23, -}; - -enum tls_handshake_type { - TLS_HELLO_REQUEST = 0, - TLS_CLIENT_HELLO = 1, - TLS_SERVER_HELLO = 2, - TLS_CERTIFICATE = 11, - TLS_SERVER_KEY_EXCHANGE = 12, - TLS_CERTIFICATE_REQUEST = 13, - TLS_SERVER_HELLO_DONE = 14, - TLS_CERTIFICATE_VERIFY = 15, - TLS_CLIENT_KEY_EXCHANGE = 16, - TLS_FINISHED = 20, -}; - -struct l_tls { - bool server; - - l_tls_write_cb_t tx, rx; - l_tls_ready_cb_t ready_handle; - l_tls_disconnect_cb_t disconnected; - void *user_data; - l_tls_debug_cb_t debug_handler; - l_tls_destroy_cb_t debug_destroy; - void *debug_data; - enum l_tls_version min_version; - enum l_tls_version max_version; - - struct l_queue *ca_certs; - struct l_certchain *cert; - struct l_key *priv_key; - size_t priv_key_size; - char **subject_mask; - - struct tls_cipher_suite **cipher_suite_pref_list; - - bool in_callback; - bool pending_destroy; - - /* Record layer */ - - uint8_t *record_buf; - int record_buf_len; - int record_buf_max_len; - bool record_flush; - - uint8_t *message_buf; - int message_buf_len; - int message_buf_max_len; - enum tls_content_type message_content_type; - - /* Handshake protocol layer */ - - enum tls_handshake_state state; - struct l_checksum *handshake_hash[__HANDSHAKE_HASH_COUNT]; - uint8_t prev_digest[__HANDSHAKE_HASH_COUNT][HANDSHAKE_HASH_MAX_SIZE]; - - enum l_tls_version client_version; - enum l_tls_version negotiated_version; - bool cert_requested, cert_sent; - bool peer_authenticated; - struct l_cert *peer_cert; - struct l_key *peer_pubkey; - size_t peer_pubkey_size; - enum handshake_hash_type signature_hash; - const struct tls_hash_algorithm *prf_hmac; - const struct tls_named_group *negotiated_curve; - const struct tls_named_group *negotiated_ff_group; - - /* SecurityParameters current and pending */ - - struct { - struct tls_cipher_suite *cipher_suite; - struct tls_compression_method *compression_method; - uint8_t master_secret[48]; - uint8_t client_random[32]; - uint8_t server_random[32]; - /* - * Max key block size per 6.3 v1.1 is 136 bytes but if we - * allow AES_256_CBC_SHA256 with v1.0 we get 128 per section - * 6.3 v1.2 + two IVs of 32 bytes. - */ - uint8_t key_block[192]; - void *key_xchg_params; - } pending; - - enum tls_cipher_type cipher_type[2]; - struct tls_cipher_suite *cipher_suite[2]; - union { - struct l_cipher *cipher[2]; - struct l_aead_cipher *aead_cipher[2]; - }; - struct l_checksum *mac[2]; - size_t mac_length[2]; - size_t block_length[2]; - size_t record_iv_length[2]; - size_t fixed_iv_length[2]; - uint8_t fixed_iv[2][32]; - size_t auth_tag_length[2]; - uint64_t seq_num[2]; - /* - * Some of the key and IV parts of the "current" state are kept - * inside the cipher and mac states in the kernel so we don't - * duplicate them here. - */ - - bool ready; -}; - -bool tls10_prf(const void *secret, size_t secret_len, - const char *label, - const void *seed, size_t seed_len, - uint8_t *out, size_t out_len); - -bool tls12_prf(enum l_checksum_type type, - const void *secret, size_t secret_len, - const char *label, - const void *seed, size_t seed_len, - uint8_t *out, size_t out_len); - -void tls_disconnect(struct l_tls *tls, enum l_tls_alert_desc desc, - enum l_tls_alert_desc local_desc); - -void tls_tx_record(struct l_tls *tls, enum tls_content_type type, - const uint8_t *data, size_t len); -bool tls_handle_message(struct l_tls *tls, const uint8_t *message, - int len, enum tls_content_type type, uint16_t version); - -#define TLS_HANDSHAKE_HEADER_SIZE 4 - -void tls_tx_handshake(struct l_tls *tls, int type, uint8_t *buf, size_t length); - -bool tls_cipher_suite_is_compatible(struct l_tls *tls, - const struct tls_cipher_suite *suite, - const char **error); - -/* Optionally limit allowed cipher suites to a custom set */ -bool tls_set_cipher_suites(struct l_tls *tls, const char **suite_list); - -void tls_generate_master_secret(struct l_tls *tls, - const uint8_t *pre_master_secret, - int pre_master_secret_len); - -const struct tls_named_group *tls_find_group(uint16_t id); -const struct tls_named_group *tls_find_ff_group(const uint8_t *prime, - size_t prime_len, - const uint8_t *generator, - size_t generator_len); - -ssize_t tls_write_signature_algorithms(struct l_tls *tls, - uint8_t *buf, size_t len); -ssize_t tls_parse_signature_algorithms(struct l_tls *tls, - const uint8_t *buf, size_t len); - -int tls_parse_certificate_list(const void *data, size_t len, - struct l_certchain **out_certchain); - -#define TLS_DEBUG(fmt, args...) \ - l_util_debug(tls->debug_handler, tls->debug_data, "%s:%i " fmt, \ - __func__, __LINE__, ## args) -#define TLS_SET_STATE(new_state) \ - do { \ - TLS_DEBUG("New state %s", \ - tls_handshake_state_to_str(new_state)); \ - tls->state = new_state; \ - } while (0) -#define TLS_DISCONNECT(desc, local_desc, fmt, args...) \ - do { \ - TLS_DEBUG("Disconnect desc=%s local-desc=%s reason=" fmt,\ - l_tls_alert_to_str(desc), \ - l_tls_alert_to_str(local_desc), ## args);\ - tls_disconnect(tls, desc, local_desc); \ - } while (0) - -#define TLS_VER_FMT "1.%i" -#define TLS_VER_ARGS(version) (((version) & 0xff) - 1) - -const char *tls_handshake_state_to_str(enum tls_handshake_state state); diff --git a/ell/tls-record.c b/ell/tls-record.c deleted file mode 100644 index 505263d..0000000 --- a/ell/tls-record.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * Embedded Linux library - * - * Copyright (C) 2015 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include - -#include "private.h" -#include "tls.h" -#include "checksum.h" -#include "cipher.h" -#include "cert.h" -#include "tls-private.h" -#include "random.h" - -/* Implementation-specific max Record Layer fragment size (must be < 16kB) */ -#define TX_RECORD_MAX_LEN 4096 - -/* TLSPlaintext + TLSCompressed + TLSCiphertext headers + seq_num sizes */ -#define TX_RECORD_MAX_HEADERS (5 + 5 + 8 + 5) -#define TX_RECORD_MAX_MAC 64 - -/* Head room and tail room for the buffer passed to the cipher */ -#define TX_RECORD_HEADROOM TX_RECORD_MAX_HEADERS -#define TX_RECORD_TAILROOM TX_RECORD_MAX_MAC - -static void tls_write_mac(struct l_tls *tls, uint8_t *compressed, - uint16_t compressed_len, uint8_t *out_buf, - bool txrx) -{ - uint8_t *in_buf; - - /* Prepend the sequence number to the TLSCompressed buffer */ - in_buf = compressed - 8; - l_put_be64(tls->seq_num[txrx]++, in_buf); - - if (tls->mac[txrx]) { - l_checksum_reset(tls->mac[txrx]); - l_checksum_update(tls->mac[txrx], in_buf, compressed_len + 8); - l_checksum_get_digest(tls->mac[txrx], out_buf, - tls->mac_length[txrx]); - } -} - -static void tls_tx_record_plaintext(struct l_tls *tls, - uint8_t *plaintext, - uint16_t plaintext_len) -{ - uint8_t *compressed; - uint16_t compressed_len; - uint8_t *cipher_input; - uint16_t cipher_input_len; - uint8_t *ciphertext; - uint16_t ciphertext_len; - uint8_t padding_length; - uint8_t buf[TX_RECORD_HEADROOM + TX_RECORD_MAX_LEN + - TX_RECORD_TAILROOM]; - uint8_t iv[32]; - uint8_t *assocdata; - int offset; - - /* - * TODO: if DEFLATE is selected in current state, use a new buffer - * on stack to write a TLSCompressed structure there, otherwise use - * the provided buffer. Since only null compression is supported - * today we always use the provided buffer. - */ - compressed_len = plaintext_len - 5; - compressed = plaintext; - - /* Build a TLSCompressed struct */ - compressed[0] = plaintext[0]; /* Copy type and version fields */ - compressed[1] = plaintext[1]; - compressed[2] = plaintext[2]; - compressed[3] = compressed_len >> 8; - compressed[4] = compressed_len >> 0; - - switch (tls->cipher_type[1]) { - case TLS_CIPHER_STREAM: - /* Append the MAC after TLSCompressed.fragment, if needed */ - tls_write_mac(tls, compressed, compressed_len + 5, - compressed + compressed_len + 5, true); - - cipher_input = compressed + 5; - cipher_input_len = compressed_len + tls->mac_length[1]; - - if (!tls->cipher[1]) { - ciphertext = cipher_input; - ciphertext_len = cipher_input_len; - } else { - ciphertext = buf + TX_RECORD_HEADROOM; - ciphertext_len = cipher_input_len; - l_cipher_encrypt(tls->cipher[1], cipher_input, - ciphertext, cipher_input_len); - } - - break; - - case TLS_CIPHER_BLOCK: - /* Append the MAC after TLSCompressed.fragment, if needed */ - cipher_input = compressed + 5; - tls_write_mac(tls, compressed, compressed_len + 5, - cipher_input + compressed_len, true); - cipher_input_len = compressed_len + tls->mac_length[1]; - - /* Add minimum padding */ - padding_length = (~cipher_input_len) & - (tls->block_length[1] - 1); - memset(cipher_input + cipher_input_len, padding_length, - padding_length + 1); - cipher_input_len += padding_length + 1; - - /* Generate an IV */ - ciphertext = buf + TX_RECORD_HEADROOM; - - offset = 0; - - if (tls->negotiated_version >= L_TLS_V12) { - l_getrandom(ciphertext, tls->record_iv_length[1]); - - l_cipher_set_iv(tls->cipher[1], ciphertext, - tls->record_iv_length[1]); - - offset = tls->record_iv_length[1]; - } else if (tls->negotiated_version >= L_TLS_V11) { - l_getrandom(iv, tls->record_iv_length[1]); - - l_cipher_encrypt(tls->cipher[1], iv, ciphertext, - tls->record_iv_length[1]); - - offset = tls->record_iv_length[1]; - } - - l_cipher_encrypt(tls->cipher[1], cipher_input, - ciphertext + offset, cipher_input_len); - ciphertext_len = offset + cipher_input_len; - - break; - - case TLS_CIPHER_AEAD: - /* Prepend seq_num to TLSCompressed.type + .version + .length */ - assocdata = compressed - 8; - l_put_be64(tls->seq_num[1]++, assocdata); - - cipher_input = compressed + 5; - cipher_input_len = compressed_len; - - /* - * Build the IV. The explicit part generation method is - * actually cipher suite-specific but our only AEAD cipher - * suites only require this part to be unique for each - * record. For future suites there may need to be a callback - * that generates the per-record IV or an enum for the suite - * to select one of a few IV types. - * - * Note kernel's rfc4106(gcm(...)) algorithm could potentially - * be used to build the IV. - */ - memcpy(iv, tls->fixed_iv[1], tls->fixed_iv_length[1]); - l_put_le64(tls->seq_num[1], iv + tls->fixed_iv_length[1]); - - if (tls->record_iv_length[1] > 8) - memset(iv + tls->fixed_iv_length[1] + 8, 42, - tls->record_iv_length[1] - 8); - - /* Build the GenericAEADCipher struct */ - ciphertext = buf + TX_RECORD_HEADROOM; - memcpy(ciphertext, iv + tls->fixed_iv_length[1], - tls->record_iv_length[1]); - l_aead_cipher_encrypt(tls->aead_cipher[1], - cipher_input, cipher_input_len, - assocdata, 13, - iv, tls->fixed_iv_length[1] + - tls->record_iv_length[1], - ciphertext + tls->record_iv_length[1], - cipher_input_len + - tls->auth_tag_length[1]); - - ciphertext_len = tls->record_iv_length[1] + - cipher_input_len + tls->auth_tag_length[1]; - - break; - - default: - return; - } - - /* Build a TLSCiphertext struct */ - ciphertext -= 5; - ciphertext[0] = plaintext[0]; /* Copy type and version fields */ - ciphertext[1] = plaintext[1]; - ciphertext[2] = plaintext[2]; - ciphertext[3] = ciphertext_len >> 8; - ciphertext[4] = ciphertext_len >> 0; - - tls->tx(ciphertext, ciphertext_len + 5, tls->user_data); -} - -void tls_tx_record(struct l_tls *tls, enum tls_content_type type, - const uint8_t *data, size_t len) -{ - uint8_t buf[TX_RECORD_HEADROOM + TX_RECORD_MAX_LEN + - TX_RECORD_TAILROOM]; - uint8_t *fragment, *plaintext; - uint16_t fragment_len; - uint16_t version = tls->negotiated_version ?: tls->min_version; - - if (type == TLS_CT_ALERT) - tls->record_flush = true; - - while (len) { - fragment = buf + TX_RECORD_HEADROOM; - fragment_len = len < TX_RECORD_MAX_LEN ? - len : TX_RECORD_MAX_LEN; - - /* Build a TLSPlaintext struct */ - plaintext = fragment - 5; - plaintext[0] = type; - plaintext[1] = (uint8_t) (version >> 8); - plaintext[2] = (uint8_t) (version >> 0); - plaintext[3] = fragment_len >> 8; - plaintext[4] = fragment_len >> 0; - memcpy(plaintext + 5, data, fragment_len); - - tls_tx_record_plaintext(tls, plaintext, fragment_len + 5); - - data += fragment_len; - len -= fragment_len; - } -} - -static bool tls_handle_plaintext(struct l_tls *tls, const uint8_t *plaintext, - int len, uint8_t type, uint16_t version) -{ - if (len > (1 << 14)) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "Plaintext message too long: %i", len); - return false; - } - - switch (type) { - case TLS_CT_CHANGE_CIPHER_SPEC: - case TLS_CT_APPLICATION_DATA: - return tls_handle_message(tls, plaintext, len, type, version); - - /* - * We need to perform input reassembly twice at different levels: - * once to make sure we're handling complete TLSCiphertext messages, - * in l_tls_handle_rx(), and again here so that the Alert and - * Handshake message type handlers deal with complete messages. - * This does not affect ChangeCipherSpec messages because they're - * just a single byte and there are never more than one such message - * in a row. Similarly it doesn't affect application data because - * the application is not guaranteed that message boundaries are - * preserved in any way and we don't know its message lengths anyway. - * It does affect Alert because these messages are 2 byte long and - * could potentially be split over two TLSPlaintext messages but - * there are never more than one Alert in a TLSPlaintext for the same - * reason as with ChangeCipherSpec. Handshake messages are the - * most affected although the need to do the reassembly twice still - * seems wasteful considering most of these messages are sent in - * plaintext and TLSCiphertext maps to TLSPlaintext records. - */ - case TLS_CT_ALERT: - case TLS_CT_HANDSHAKE: - break; - - default: - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "Unknown content type %i", type); - return false; - } - - if (tls->message_buf_len && type != tls->message_content_type) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "Message fragment type %i doesn't match " - "previous type %i", type, - tls->message_content_type); - return false; - } - - tls->message_content_type = type; - - while (1) { - int header_len, need_len; - int chunk_len; - - /* Do we have a full header in tls->message_buf? */ - header_len = (type == TLS_CT_ALERT) ? 2 : 4; - need_len = header_len; - - if (tls->message_buf_len >= header_len) { - if (type == TLS_CT_HANDSHAKE) { - uint32_t hs_len = (tls->message_buf[1] << 16) | - (tls->message_buf[2] << 8) | - (tls->message_buf[3] << 0); - if (hs_len > (1 << 14)) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, - 0, "Handshake message " - "too long: %i", - (int) hs_len); - return false; - } - - need_len += hs_len; - } - - /* Do we have a full structure? */ - if (tls->message_buf_len == need_len) { - if (!tls_handle_message(tls, tls->message_buf, - need_len, type, - version)) - return false; - - tls->message_buf_len = 0; - - if (tls->record_flush) - break; - - continue; - } - - if (!len) - break; - } - - /* Try to fill up tls->message_buf up to need_len */ - if (tls->message_buf_max_len < need_len) { - tls->message_buf_max_len = need_len; - tls->message_buf = - l_realloc(tls->message_buf, need_len); - } - - need_len -= tls->message_buf_len; - chunk_len = need_len; - if (len < chunk_len) - chunk_len = len; - - memcpy(tls->message_buf + tls->message_buf_len, plaintext, - chunk_len); - tls->message_buf_len += chunk_len; - plaintext += chunk_len; - len -= chunk_len; - - if (chunk_len < need_len) - break; - } - - return true; -} - -static bool tls_handle_ciphertext(struct l_tls *tls) -{ - uint8_t type; - uint16_t version; - uint16_t fragment_len; - uint8_t mac_buf[TX_RECORD_MAX_MAC], i, padding_len; - int cipher_output_len, error; - uint8_t *compressed; - int compressed_len; - uint8_t iv[32]; - uint8_t *assocdata; - - type = tls->record_buf[0]; - version = l_get_be16(tls->record_buf + 1); - fragment_len = l_get_be16(tls->record_buf + 3); - - if (fragment_len > (1 << 14) + 2048) { - TLS_DISCONNECT(TLS_ALERT_RECORD_OVERFLOW, 0, - "Record fragment too long: %u", fragment_len); - return false; - } - - if ((tls->negotiated_version && tls->negotiated_version != version) || - (!tls->negotiated_version && - tls->record_buf[1] != 0x03 /* Appending E.1 */)) { - TLS_DISCONNECT(TLS_ALERT_PROTOCOL_VERSION, 0, - "Record version mismatch: %02x", version); - return false; - } - - if (fragment_len < tls->mac_length[0]) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "Record fragment too short: %u", fragment_len); - return false; - } - - compressed = alloca(8 + 5 + fragment_len); - /* Copy the type and version fields */ - compressed[8] = type; - l_put_be16(version, compressed + 9); - - switch (tls->cipher_type[0]) { - case TLS_CIPHER_STREAM: - cipher_output_len = fragment_len; - compressed_len = cipher_output_len - tls->mac_length[0]; - l_put_be16(compressed_len, compressed + 11); - - if (!tls->cipher[0]) - memcpy(compressed + 13, tls->record_buf + 5, - cipher_output_len); - else if (!l_cipher_decrypt(tls->cipher[0], tls->record_buf + 5, - compressed + 13, - cipher_output_len)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Decrypting record fragment failed"); - return false; - } - - /* Calculate the MAC if needed */ - tls_write_mac(tls, compressed + 8, 5 + compressed_len, - mac_buf, false); - - if (memcmp(mac_buf, compressed + 13 + compressed_len, - tls->mac_length[0])) { - TLS_DISCONNECT(TLS_ALERT_BAD_RECORD_MAC, 0, - "Record fragment MAC mismatch"); - return false; - } - - compressed += 13; - - break; - - case TLS_CIPHER_BLOCK: - i = 0; - if (tls->negotiated_version >= L_TLS_V11) - i = tls->record_iv_length[0]; - - if (fragment_len <= tls->mac_length[0] + i) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "Record fragment too short: %u", - fragment_len); - return false; - } - - cipher_output_len = fragment_len - i; - - if (cipher_output_len % tls->block_length[0] != 0) { - /* - * In strict TLS 1.0 TLS_ALERT_DECRYPT_FAIL_RESERVED - * should be returned here but that was declared - * unsafe in the TLS 1.1 spec. - */ - TLS_DISCONNECT(TLS_ALERT_BAD_RECORD_MAC, 0, - "Fragment data len %i not a multiple " - "of block length %zi", - cipher_output_len, - tls->block_length[0]); - return false; - } - - if (tls->negotiated_version >= L_TLS_V12) { - if (!l_cipher_set_iv(tls->cipher[0], - tls->record_buf + 5, - tls->record_iv_length[0])) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Setting fragment IV failed"); - return false; - } - } else if (tls->negotiated_version >= L_TLS_V11) - if (!l_cipher_decrypt(tls->cipher[0], - tls->record_buf + 5, iv, - tls->record_iv_length[0])) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Setting fragment IV failed"); - return false; - } - - if (!l_cipher_decrypt(tls->cipher[0], tls->record_buf + 5 + i, - compressed + 13, cipher_output_len)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Fragment decryption failed"); - return false; - } - - /* - * RFC 5246, page 24: - * In order to defend against this attack, implementations - * MUST ensure that record processing time is essentially the - * same whether or not the padding is correct. In general, - * the best way to do this is to compute the MAC even if the - * padding is incorrect, and only then reject the packet. For - * instance, if the pad appears to be incorrect, the - * implementation might assume a zero-length pad and then - * compute the MAC. - */ - padding_len = compressed[13 + cipher_output_len - 1]; - error = 0; - if (padding_len + tls->mac_length[0] + 1 > - (size_t) cipher_output_len) { - /* - * In strict TLS 1.0 TLS_ALERT_DECRYPT_FAIL_RESERVED - * should be returned here but that was declared - * unsafe in the TLS 1.1 spec. - */ - padding_len = 0; - error = 1; - } - - compressed_len = cipher_output_len - 1 - padding_len - - tls->mac_length[0]; - l_put_be16(compressed_len, compressed + 11); - - for (i = 0; i < padding_len; i++) - if (compressed[13 + cipher_output_len - 1 - - padding_len + i] != padding_len) - error = 1; - - /* Calculate the MAC if needed */ - tls_write_mac(tls, compressed + 8, 5 + compressed_len, - mac_buf, false); - - if ((tls->mac_length[0] && memcmp(mac_buf, compressed + 13 + - compressed_len, tls->mac_length[0])) || - error) { - TLS_DISCONNECT(TLS_ALERT_BAD_RECORD_MAC, 0, - "Record fragment MAC mismatch"); - return false; - } - - compressed += 13; - - break; - - case TLS_CIPHER_AEAD: - if (fragment_len <= tls->record_iv_length[0] + - tls->auth_tag_length[0]) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "Record fragment too short: %u", - fragment_len); - return false; - } - - compressed_len = fragment_len - tls->record_iv_length[0] - - tls->auth_tag_length[0]; - l_put_be16(compressed_len, compressed + 11); - - /* Prepend seq_num to TLSCompressed.type + .version + .length */ - assocdata = compressed; - l_put_be64(tls->seq_num[0]++, assocdata); - compressed += 13; - - /* Build the IV */ - memcpy(iv, tls->fixed_iv[0], tls->fixed_iv_length[0]); - memcpy(iv + tls->fixed_iv_length[0], tls->record_buf + 5, - tls->record_iv_length[0]); - - if (!l_aead_cipher_decrypt(tls->aead_cipher[0], - tls->record_buf + 5 + tls->record_iv_length[0], - fragment_len - tls->record_iv_length[0], - assocdata, 13, iv, tls->fixed_iv_length[0] + - tls->record_iv_length[0], - compressed, compressed_len)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Decrypting record fragment failed"); - return false; - } - - break; - - default: - return false; - } - - /* DEFLATE not supported so just pass on compressed / compressed_len */ - - return tls_handle_plaintext(tls, compressed, compressed_len, - type, version); -} - -LIB_EXPORT void l_tls_handle_rx(struct l_tls *tls, const uint8_t *data, - size_t len) -{ - int need_len; - int chunk_len; - - tls->record_flush = false; - - /* Reassemble TLSCiphertext structures from the received chunks */ - - while (1) { - /* Do we have a full header in tls->record_buf? */ - if (tls->record_buf_len >= 5) { - need_len = 5 + l_get_be16(tls->record_buf + 3); - - /* Do we have a full structure? */ - if (tls->record_buf_len == need_len) { - if (!tls_handle_ciphertext(tls)) - return; - - tls->record_buf_len = 0; - need_len = 5; - - if (tls->record_flush) - break; - } - - if (!len) - break; - } else - need_len = 5; - - /* Try to fill up tls->record_buf up to need_len */ - if (tls->record_buf_max_len < need_len) { - tls->record_buf_max_len = need_len; - tls->record_buf = l_realloc(tls->record_buf, need_len); - } - - need_len -= tls->record_buf_len; - chunk_len = need_len; - if (len < (size_t) chunk_len) - chunk_len = len; - - memcpy(tls->record_buf + tls->record_buf_len, data, chunk_len); - tls->record_buf_len += chunk_len; - data += chunk_len; - len -= chunk_len; - - if (chunk_len < need_len) - break; - } -} diff --git a/ell/tls-suites.c b/ell/tls-suites.c deleted file mode 100644 index 91bc2cf..0000000 --- a/ell/tls-suites.c +++ /dev/null @@ -1,1373 +0,0 @@ -/* - * Embedded Linux library - * - * Copyright (C) 2018 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include -#include -#include -#include - -#include "util.h" -#include "tls.h" -#include "cipher.h" -#include "checksum.h" -#include "cert.h" -#include "tls-private.h" -#include "key.h" -#include "random.h" -#include "ecc.h" -#include "ecdh.h" -#include "missing.h" - -static bool tls_rsa_validate_cert_key(struct l_cert *cert) -{ - return l_cert_get_pubkey_type(cert) == L_CERT_KEY_RSA; -} - -static ssize_t tls_rsa_sign(struct l_tls *tls, uint8_t *out, size_t out_len, - tls_get_hash_t get_hash, - const uint8_t *data, size_t data_len) -{ - ssize_t result = -EMSGSIZE; - enum l_checksum_type sign_checksum_type; - uint8_t sign_input[HANDSHAKE_HASH_MAX_SIZE + 36]; - size_t sign_input_len; - uint8_t *ptr = out; - - if (!tls->priv_key || !tls->priv_key_size) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, TLS_ALERT_BAD_CERT, - "No private key loaded"); - - return -ENOKEY; - } - - if (tls->negotiated_version >= L_TLS_V12) { - const struct tls_hash_algorithm *hash_type = - &tls_handshake_hash_data[tls->signature_hash]; - - /* Build the DigitallySigned struct */ - if (out_len < 2) /* Is there space for the algorithm IDs */ - goto error; - - get_hash(tls, tls->signature_hash, data, data_len, - sign_input, &sign_input_len); - sign_checksum_type = hash_type->l_id; - - *ptr++ = hash_type->tls_id; - *ptr++ = 1; /* RSA_sign */ - out_len -= 2; - } else { - get_hash(tls, HANDSHAKE_HASH_MD5, data, data_len, - sign_input + 0, NULL); - get_hash(tls, HANDSHAKE_HASH_SHA1, data, data_len, - sign_input + 16, NULL); - sign_checksum_type = L_CHECKSUM_NONE; - sign_input_len = 36; - } - - if (out_len < tls->priv_key_size + 2) - goto error; - - l_put_be16(tls->priv_key_size, ptr); - result = l_key_sign(tls->priv_key, L_KEY_RSA_PKCS1_V1_5, - sign_checksum_type, sign_input, ptr + 2, - sign_input_len, tls->priv_key_size); - ptr += tls->priv_key_size + 2; - - if (result == (ssize_t) tls->priv_key_size) - return ptr - out; /* Success */ - -error: - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Signing the hash failed: %s", - strerror(-result)); - return result; -} - -static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t in_len, - tls_get_hash_t get_hash, - const uint8_t *data, size_t data_len) -{ - enum l_checksum_type sign_checksum_type; - uint8_t expected[HANDSHAKE_HASH_MAX_SIZE + 36]; - size_t expected_len; - unsigned int offset; - bool success; - - /* 2 bytes for SignatureAndHashAlgorithm if version >= 1.2 */ - offset = 2; - if (tls->negotiated_version < L_TLS_V12) - offset = 0; - - if (in_len < offset + 2 || - (size_t) l_get_be16(in + offset) + offset + 2 != - in_len) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, "Signature msg too " - "short (%zi) or signature length doesn't match", - in_len); - - return false; - } - - /* Only the default hash type supported */ - if (in_len != offset + 2 + tls->peer_pubkey_size) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "Signature length %zi not equal %zi", in_len, - offset + 2 + tls->peer_pubkey_size); - - return false; - } - - if (tls->negotiated_version >= L_TLS_V12) { - enum handshake_hash_type hash; - - /* Only RSA supported */ - if (in[1] != 1 /* RSA_sign */) { - TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0, - "Unknown signature algorithm %i", - in[1]); - - return false; - } - - for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) - if (tls_handshake_hash_data[hash].tls_id == in[0]) - break; - - if (hash == __HANDSHAKE_HASH_COUNT) { - TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0, - "Unknown hash type %i", in[0]); - return false; - } - - get_hash(tls, hash, data, data_len, expected, &expected_len); - sign_checksum_type = tls_handshake_hash_data[hash].l_id; - - /* - * Note: Next we let the l_key_verify's underlying kernel - * operation prepend the OID to the hash to build the - * DigestInfo struct. However according to 4.7 we need to - * support at least two forms of the signed content in the - * verification: - * - DigestInfo with NULL AlgorithmIdentifier.parameters, - * - DigestInfo with empty AlgorithmIdentifier.parameters, - * - * while the kernel only understands the former encoding. - * Note PKCS#1 versions 2.0 and later section A.2.4 do - * mandate NULL AlgorithmIdentifier.parameters. - * - * Additionally PKCS#1 v1.5 said BER is used in place of DER - * for DigestInfo encoding which adds more ambiguity in the - * encoding. - */ - } else { - get_hash(tls, HANDSHAKE_HASH_MD5, data, data_len, - expected + 0, NULL); - get_hash(tls, HANDSHAKE_HASH_SHA1, data, data_len, - expected + 16, NULL); - expected_len = 36; - sign_checksum_type = L_CHECKSUM_NONE; - - /* - * Note: Within the RSA padding for signatures PKCS#1 1.5 - * allows the block format to be either 0 or 1, while PKCS#1 - * v2.0+ mandates block type 1 making the signatures - * unambiguous. TLS 1.0 doesn't additionally specify which - * block type is to be used (TLS 1.2 does) meaning that both - * PKCS#1 v1.5 types are allowed. The l_key_verify's - * underlying kernel implementation only accepts block type - * 1. If this ever becomes an issue we'd need to go back to - * using L_KEY_RSA_RAW and our own PKCS#1 v1.5 verify logic. - */ - } - - success = l_key_verify(tls->peer_pubkey, L_KEY_RSA_PKCS1_V1_5, - sign_checksum_type, expected, in + offset + 2, - expected_len, tls->peer_pubkey_size); - - if (!success) - TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0, - "Peer signature verification failed"); - else - TLS_DEBUG("Peer signature verified"); - - return success; -} - -static struct tls_signature_algorithm tls_rsa_signature = { - .id = 1, /* SignatureAlgorithm.rsa */ - .validate_cert_key_type = tls_rsa_validate_cert_key, - .sign = tls_rsa_sign, - .verify = tls_rsa_verify, -}; - -static bool tls_send_rsa_client_key_xchg(struct l_tls *tls) -{ - uint8_t buf[1024 + 32]; - uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; - uint8_t pre_master_secret[48]; - ssize_t bytes_encrypted; - - if (!tls->peer_pubkey) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Peer public key not received"); - - return false; - } - - /* Must match the version in tls_send_client_hello */ - pre_master_secret[0] = (uint8_t) (tls->max_version >> 8); - pre_master_secret[1] = (uint8_t) (tls->max_version >> 0); - - l_getrandom(pre_master_secret + 2, 46); - - if (tls->peer_pubkey_size + 32 > (int) sizeof(buf)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Peer public key too big: %zi", - tls->peer_pubkey_size); - - return false; - } - - l_put_be16(tls->peer_pubkey_size, ptr); - bytes_encrypted = l_key_encrypt(tls->peer_pubkey, - L_KEY_RSA_PKCS1_V1_5, L_CHECKSUM_NONE, - pre_master_secret, ptr + 2, 48, - tls->peer_pubkey_size); - ptr += tls->peer_pubkey_size + 2; - - if (bytes_encrypted != (ssize_t) tls->peer_pubkey_size) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Encrypting PreMasterSecret failed: %s", - strerror(-bytes_encrypted)); - - return false; - } - - tls_tx_handshake(tls, TLS_CLIENT_KEY_EXCHANGE, buf, ptr - buf); - - tls_generate_master_secret(tls, pre_master_secret, 48); - explicit_bzero(pre_master_secret, 48); - - return true; -} - -static void tls_handle_rsa_client_key_xchg(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - uint8_t pre_master_secret[48], random_secret[46]; - ssize_t bytes_decrypted; - - if (!tls->priv_key || !tls->priv_key_size) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, TLS_ALERT_BAD_CERT, - "No private key"); - - return; - } - - if (len != tls->priv_key_size + 2) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "ClientKeyExchange len %zi not %zi", len, - tls->priv_key_size + 2); - - return; - } - - len = l_get_be16(buf); - - if (len != tls->priv_key_size) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "EncryptedPreMasterSecret len %zi not %zi", - len, tls->priv_key_size); - - return; - } - - bytes_decrypted = l_key_decrypt(tls->priv_key, L_KEY_RSA_PKCS1_V1_5, - L_CHECKSUM_NONE, buf + 2, - pre_master_secret, tls->priv_key_size, - 48); - - /* - * Assume correct premaster secret client version which according - * to the TLS1.2 spec is unlikely in client implementations SSLv3 - * and prior. Spec suggests either not supporting them or adding - * a configurable override for <= SSLv3 clients. For now we have - * no need to support them. - * - * On any decode error randomise the Pre Master Secret as per the - * countermeasures in 7.4.7.1 and don't generate any alerts. - */ - l_getrandom(random_secret, 46); - - pre_master_secret[0] = tls->client_version >> 8; - pre_master_secret[1] = tls->client_version >> 0; - - if (bytes_decrypted != 48) { - memcpy(pre_master_secret + 2, random_secret, 46); - - TLS_DEBUG("Error decrypting PreMasterSecret: %s", - strerror(-bytes_decrypted)); - } - - tls_generate_master_secret(tls, pre_master_secret, 48); - explicit_bzero(pre_master_secret, 48); - explicit_bzero(random_secret, 46); -} - -static struct tls_key_exchange_algorithm tls_rsa_key_xchg = { - .send_client_key_exchange = tls_send_rsa_client_key_xchg, - .handle_client_key_exchange = tls_handle_rsa_client_key_xchg, -}; - -/* Used by both DHE and ECDHE */ -static bool tls_get_dh_params_hash(struct l_tls *tls, - enum handshake_hash_type type, - const uint8_t *data, size_t data_len, - uint8_t *out, size_t *out_len) -{ - struct l_checksum *checksum; - ssize_t ret; - - /* - * The ServerKeyExchange signature hash input format for RSA_sign is - * not really specified in either RFC 8422 or RFC 5246 explicitly - * but we use this format by analogy to DHE_RSA which uses RSA_sign - * as well. Also matches ecdsa, ed25519 and ed448 formats. - */ - struct iovec iov[] = { - { .iov_base = tls->pending.client_random, .iov_len = 32 }, - { .iov_base = tls->pending.server_random, .iov_len = 32 }, - { .iov_base = (void *) data, .iov_len = data_len }, - }; - - checksum = l_checksum_new(tls_handshake_hash_data[type].l_id); - if (!checksum) - return false; - - l_checksum_updatev(checksum, iov, L_ARRAY_SIZE(iov)); - ret = l_checksum_get_digest(checksum, out, HANDSHAKE_HASH_MAX_SIZE); - l_checksum_free(checksum); - - if (ret < 0) - return false; - - if (out_len) - *out_len = ret; - - return true; -} - -struct tls_ecdhe_params { - const struct l_ecc_curve *curve; - struct l_ecc_scalar *private; - struct l_ecc_point *public; -}; - -static void tls_free_ecdhe_params(struct l_tls *tls) -{ - struct tls_ecdhe_params *params = tls->pending.key_xchg_params; - - if (!params) - return; - - tls->pending.key_xchg_params = NULL; - - l_ecc_scalar_free(params->private); - l_ecc_point_free(params->public); - l_free(params); -} - -static size_t tls_write_ecpoint(uint8_t *buf, size_t len, - const struct tls_named_group *curve, - const struct l_ecc_point *point) -{ - size_t point_bytes; - - /* RFC 8422, Section 5.4.1 */ - point_bytes = l_ecc_point_get_data(point, buf + 2, len - 2); - buf[0] = 1 + point_bytes; /* length */ - buf[1] = 4; /* form: uncompressed */ - return 2 + point_bytes; -} - -static size_t tls_write_server_ecdh_params(struct l_tls *tls, uint8_t *buf, size_t len) -{ - struct tls_ecdhe_params *params = tls->pending.key_xchg_params; - - /* RFC 8422, Section 5.4 */ - buf[0] = 3; /* curve_type: named_curve */ - l_put_be16(tls->negotiated_curve->id, buf + 1); - return 3 + tls_write_ecpoint(buf + 3, len - 3, tls->negotiated_curve, - params->public); -} - -static bool tls_send_ecdhe_server_key_xchg(struct l_tls *tls) -{ - uint8_t buf[1024]; - uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; - struct tls_ecdhe_params *params; - ssize_t sign_len; - const uint8_t *server_ecdh_params_ptr; - - /* - * RFC 8422, Section 5.4 - * - * If we're getting here we can assume that tls->pending.key_xchg_params - * is NULL, tls->priv_key is our signing key and tls->negotiated_curve - * is non-NULL. - */ - - params = l_new(struct tls_ecdhe_params, 1); - params->curve = l_ecc_curve_get_tls_group(tls->negotiated_curve->id); - tls->pending.key_xchg_params = params; - - if (!l_ecdh_generate_key_pair(params->curve, - ¶ms->private, ¶ms->public)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Generating ECDH key pair failed"); - return false; - } - - server_ecdh_params_ptr = ptr; - ptr += tls_write_server_ecdh_params(tls, ptr, buf + sizeof(buf) - ptr); - - if (tls->pending.cipher_suite->signature) { - sign_len = tls->pending.cipher_suite->signature->sign(tls, ptr, - buf + sizeof(buf) - ptr, - tls_get_dh_params_hash, - server_ecdh_params_ptr, - ptr - server_ecdh_params_ptr); - if (sign_len < 0) - return false; - - ptr += sign_len; - } - - tls_tx_handshake(tls, TLS_SERVER_KEY_EXCHANGE, buf, ptr - buf); - - return true; -} - -static void tls_handle_ecdhe_server_key_xchg(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - struct tls_ecdhe_params *params; - uint16_t namedcurve; - const uint8_t *server_ecdh_params_ptr = buf; - size_t point_bytes; - - /* RFC 8422, Section 5.4 */ - - if (len < 5) - goto decode_error; - - if (*buf != 3) { - TLS_DISCONNECT(TLS_ALERT_ILLEGAL_PARAM, 0, - "Unsupported (deprecated?) ECCurveType %u", - *buf); - return; - } - - namedcurve = l_get_be16(buf + 1); - buf += 3; - len -= 3; - - tls->negotiated_curve = tls_find_group(namedcurve); - - if (!tls->negotiated_curve || - tls->negotiated_curve->type != TLS_GROUP_TYPE_EC) { - TLS_DISCONNECT(TLS_ALERT_ILLEGAL_PARAM, 0, - "Unsupported NamedCurve %u", namedcurve); - return; - } - - TLS_DEBUG("Negotiated %s", tls->negotiated_curve->name); - - if (*buf < 1) - goto decode_error; - - point_bytes = *buf++ - 1; - - if (*buf != 4) { /* uncompressed */ - TLS_DISCONNECT(TLS_ALERT_ILLEGAL_PARAM, 0, - "Unsupported (deprecated?) PointConversionForm " - "%u", *buf); - return; - } - - buf++; - len -= 2; - - if (len < point_bytes) - goto decode_error; - - /* - * RFC 8422, Section 5.11: "A receiving party MUST check that the - * x and y parameters from the peer's public value satisfy the - * curve equation, y^2 = x^3 + ax + b mod p." - * This happens in l_ecc_point_from_data when the L_ECC_POINT_TYPE_FULL - * format is used. - */ - params = l_new(struct tls_ecdhe_params, 1); - params->curve = l_ecc_curve_get_tls_group(tls->negotiated_curve->id); - params->public = l_ecc_point_from_data(params->curve, - L_ECC_POINT_TYPE_FULL, - buf, len); - tls->pending.key_xchg_params = params; - buf += point_bytes; - len -= point_bytes; - - if (!params->public || point_bytes != - 2 * l_ecc_curve_get_scalar_bytes(params->curve)) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "ServerKeyExchange.params.public decode error"); - return; - } - - if (tls->pending.cipher_suite->signature) { - if (!tls->pending.cipher_suite->signature->verify(tls, buf, len, - tls_get_dh_params_hash, - server_ecdh_params_ptr, - buf - server_ecdh_params_ptr)) - return; - } else { - if (len) - goto decode_error; - } - - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO_DONE); - - return; - -decode_error: - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "ServerKeyExchange decode error"); -} - -static bool tls_send_ecdhe_client_key_xchg(struct l_tls *tls) -{ - uint8_t buf[1024]; - uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; - uint8_t pre_master_secret[128]; - ssize_t pre_master_secret_len; - struct tls_ecdhe_params *params = tls->pending.key_xchg_params; - struct l_ecc_point *our_public; - struct l_ecc_scalar *secret; - - /* RFC 8422, Section 5.7 */ - - if (!l_ecdh_generate_key_pair(params->curve, - ¶ms->private, &our_public)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Generating ECDH key pair failed"); - return false; - } - - ptr += tls_write_ecpoint(ptr, buf + sizeof(buf) - ptr, - tls->negotiated_curve, our_public); - l_ecc_point_free(our_public); - - /* - * Neither 5.4 or 5.7 "Actions" paragraphs say when the ECDH shared - * secret is calculated but we can either do this in - * tls_handle_ecdhe_server_key_xchg or here. In both cases we only - * need to store the public key in the client's key_xchg_params and - * can free all of the params after sending the ClientKeyExchange. - * By doing this calculation here we're aligned with RSA and also - * with the server mode where the shared secret can only be - * calculated after the ClientKeyExchange is received. - */ - if (!l_ecdh_generate_shared_secret(params->private, params->public, - &secret)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Generating ECDH shared-secret failed"); - return false; - } - - tls_free_ecdhe_params(tls); - pre_master_secret_len = l_ecc_scalar_get_data(secret, - pre_master_secret, - sizeof(pre_master_secret)); - l_ecc_scalar_free(secret); - - if (pre_master_secret_len < 0) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "l_ecc_scalar_get_data(secret) failed"); - return false; - } - - tls_tx_handshake(tls, TLS_CLIENT_KEY_EXCHANGE, buf, ptr - buf); - - tls_generate_master_secret(tls, pre_master_secret, - pre_master_secret_len); - explicit_bzero(pre_master_secret, pre_master_secret_len); - - return true; -} - -static void tls_handle_ecdhe_client_key_xchg(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - struct tls_ecdhe_params *params = tls->pending.key_xchg_params; - uint8_t pre_master_secret[128]; - ssize_t pre_master_secret_len; - struct l_ecc_point *other_public; - struct l_ecc_scalar *secret; - size_t point_bytes = 2 * l_ecc_curve_get_scalar_bytes(params->curve); - - /* RFC 8422, Section 5.7 */ - - if (len < 2) - goto decode_error; - - if (*buf++ != 1 + point_bytes) - goto decode_error; - - if (*buf != 4) { /* uncompressed */ - TLS_DISCONNECT(TLS_ALERT_ILLEGAL_PARAM, 0, - "Unsupported (deprecated?) PointConversionForm " - "%u", *buf); - return; - } - - buf++; - len -= 2; - - if (len != point_bytes) - goto decode_error; - - /* - * RFC 8422, Section 5.11: "A receiving party MUST check that the - * x and y parameters from the peer's public value satisfy the - * curve equation, y^2 = x^3 + ax + b mod p." - * This happens in l_ecc_point_from_data when the L_ECC_POINT_TYPE_FULL - * format is used. - */ - other_public = l_ecc_point_from_data(params->curve, - L_ECC_POINT_TYPE_FULL, - buf, len); - if (!other_public) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "ClientKeyExchange.exchange_keys.ecdh_Yc " - "decode error"); - return; - } - - if (!l_ecdh_generate_shared_secret(params->private, other_public, - &secret)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Generating ECDH shared-secret failed"); - return; - } - - tls_free_ecdhe_params(tls); - l_ecc_point_free(other_public); - pre_master_secret_len = l_ecc_scalar_get_data(secret, - pre_master_secret, - sizeof(pre_master_secret)); - l_ecc_scalar_free(secret); - - if (pre_master_secret_len < 0) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "l_ecc_scalar_get_data(secret) failed"); - return; - } - - tls_generate_master_secret(tls, pre_master_secret, - pre_master_secret_len); - explicit_bzero(pre_master_secret, pre_master_secret_len); - - return; - -decode_error: - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "ClientKeyExchange decode error"); -} - -static struct tls_key_exchange_algorithm tls_ecdhe = { - .need_ecc = true, - .send_server_key_exchange = tls_send_ecdhe_server_key_xchg, - .handle_server_key_exchange = tls_handle_ecdhe_server_key_xchg, - .send_client_key_exchange = tls_send_ecdhe_client_key_xchg, - .handle_client_key_exchange = tls_handle_ecdhe_client_key_xchg, - .free_params = tls_free_ecdhe_params, -}; - -/* Maximum FF DH prime modulus size in bytes */ -#define TLS_DHE_MAX_SIZE 1024 - -struct tls_dhe_params { - size_t prime_len; - struct l_key *prime; - struct l_key *generator; - struct l_key *private; - struct l_key *public; -}; - -static void tls_free_dhe_params(struct l_tls *tls) -{ - struct tls_dhe_params *params = tls->pending.key_xchg_params; - - if (!params) - return; - - tls->pending.key_xchg_params = NULL; - - l_key_free(params->prime); - l_key_free(params->generator); - l_key_free(params->private); - l_key_free(params->public); - l_free(params); -} - -static bool tls_send_dhe_server_key_xchg(struct l_tls *tls) -{ - uint8_t buf[1024 + TLS_DHE_MAX_SIZE * 3]; - uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; - struct tls_dhe_params *params; - const uint8_t *prime_buf; - uint8_t generator_buf = tls->negotiated_ff_group->ff.generator; - uint8_t public_buf[TLS_DHE_MAX_SIZE]; - size_t public_len; - unsigned int zeros = 0; - ssize_t sign_len; - const uint8_t *server_dh_params_ptr; - - params = l_new(struct tls_dhe_params, 1); - prime_buf = tls->negotiated_ff_group->ff.prime; - params->prime_len = tls->negotiated_ff_group->ff.prime_len; - - params->prime = l_key_new(L_KEY_RAW, prime_buf, params->prime_len); - params->generator = l_key_new(L_KEY_RAW, &generator_buf, 1); - - if (!params->prime || !params->generator) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, "l_key_new failed"); - goto free_params; - } - - params->private = l_key_generate_dh_private(prime_buf, params->prime_len); - if (!params->private) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "l_key_generate_dh_private failed"); - goto free_params; - } - - memset(public_buf, 0, sizeof(public_buf)); - public_len = params->prime_len; - - if (!l_key_compute_dh_public(params->generator, params->private, - params->prime, public_buf, - &public_len)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "l_key_compute_dh_public failed"); - goto free_params; - } - - while (zeros < public_len && public_buf[zeros] == 0x00) - zeros++; - - server_dh_params_ptr = ptr; - - /* RFC 5246, Section 7.4.3 */ - - l_put_be16(params->prime_len, ptr); - memcpy(ptr + 2, prime_buf, params->prime_len); - ptr += 2 + params->prime_len; - - l_put_be16(1, ptr); - memcpy(ptr + 2, &generator_buf, 1); - ptr += 2 + 1; - - l_put_be16(public_len - zeros, ptr); - memcpy(ptr + 2, public_buf + zeros, public_len - zeros); - ptr += 2 + public_len - zeros; - - if (tls->pending.cipher_suite->signature) { - sign_len = tls->pending.cipher_suite->signature->sign(tls, ptr, - buf + sizeof(buf) - ptr, - tls_get_dh_params_hash, - server_dh_params_ptr, - ptr - server_dh_params_ptr); - if (sign_len < 0) - goto free_params; - - ptr += sign_len; - } - - tls->pending.key_xchg_params = params; - - tls_tx_handshake(tls, TLS_SERVER_KEY_EXCHANGE, buf, ptr - buf); - return true; - -free_params: - l_key_free(params->prime); - l_key_free(params->generator); - l_key_free(params->private); - l_free(params); - return false; -} - -static void tls_handle_dhe_server_key_xchg(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - struct tls_dhe_params *params = NULL; - const uint8_t *prime_buf; - const uint8_t *generator_buf; - size_t generator_len; - const uint8_t *public_buf; - size_t public_len; - const uint8_t *server_dh_params_ptr = buf; - - if (len < 2) - goto decode_error; - - params = l_new(struct tls_dhe_params, 1); - params->prime_len = l_get_be16(buf); - if (len < 2 + params->prime_len + 2) - goto decode_error; - - prime_buf = buf + 2; - buf += 2 + params->prime_len; - len -= 2 + params->prime_len; - - /* Strip leading zeros for the length checks later */ - while (params->prime_len && prime_buf[0] == 0x00) { - prime_buf++; - params->prime_len--; - } - - generator_len = l_get_be16(buf); - if (len < 2 + generator_len + 2) - goto decode_error; - - generator_buf = buf + 2; - buf += 2 + generator_len; - len -= 2 + generator_len; - - public_len = l_get_be16(buf); - if (len < 2 + public_len) - goto decode_error; - - public_buf = buf + 2; - buf += 2 + public_len; - len -= 2 + public_len; - - /* - * Validate the values received. Without requiring RFC 7919 from - * the server, and there are many servers that don't implement it - * yet, we basically have to blindly accept the provided prime value. - * We have no way to confirm that it's actually prime or that it's a - * "safe prime" or that it forms a group without small sub-groups. - * There's also no way to whitelist all valid values. But we do a - * basic sanity check and require it to be 1536-bit or longer, the - * minimum length required by the Linux kernel for keyctl_dh_compute(). - * The generator must also be at least within the min & max interval - * for the private/public values. - */ - - if (params->prime_len > TLS_DHE_MAX_SIZE || params->prime_len < 192 || - !(prime_buf[params->prime_len - 1] & 1)) { - TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, - "Server DH prime modulus invalid"); - goto free_params; - } - - if (!l_key_validate_dh_payload(generator_buf, generator_len, - prime_buf, params->prime_len)) { - TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, - "Server DH generator value invalid"); - goto free_params; - } - - /* - * Just output a warning if the server sent group parameters not - * offered in our RFC 7919 Supported Groups extension. - */ - if (!tls_find_ff_group(prime_buf, params->prime_len, - generator_buf, generator_len)) - TLS_DEBUG("Warning: using server's custom %i-bit FF DH group", - (int) (params->prime_len * 8)); - - /* - * RFC 7919 Section 3.0: - * "the client MUST verify that dh_Ys is in the range - * 1 < dh_Ys < dh_p - 1. If dh_Ys is not in this range, the client - * MUST terminate the connection with a fatal handshake_failure(40) - * alert." - */ - if (!l_key_validate_dh_payload(public_buf, public_len, - prime_buf, params->prime_len)) { - TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, - "Server DH public value invalid"); - goto free_params; - } - - params->prime = l_key_new(L_KEY_RAW, prime_buf, params->prime_len); - params->generator = l_key_new(L_KEY_RAW, generator_buf, generator_len); - params->public = l_key_new(L_KEY_RAW, public_buf, public_len); - - if (!params->prime || !params->generator || !params->public) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, "l_key_new failed"); - goto free_params; - } - - /* Do this now so we don't need prime_buf in send_client_key_xchg */ - params->private = l_key_generate_dh_private(prime_buf, params->prime_len); - if (!params->private) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "l_key_generate_dh_private failed"); - goto free_params; - } - - tls->pending.key_xchg_params = params; - - if (tls->pending.cipher_suite->signature) { - if (!tls->pending.cipher_suite->signature->verify(tls, buf, len, - tls_get_dh_params_hash, - server_dh_params_ptr, - buf - server_dh_params_ptr)) - return; - } else { - if (len) - goto decode_error; - } - - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO_DONE); - return; - -decode_error: - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "ServerKeyExchange decode error"); - -free_params: - if (params) { - l_key_free(params->prime); - l_key_free(params->generator); - l_key_free(params->public); - l_free(params); - } -} - -static bool tls_send_dhe_client_key_xchg(struct l_tls *tls) -{ - struct tls_dhe_params *params = tls->pending.key_xchg_params; - uint8_t buf[128 + params->prime_len]; - uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; - uint8_t public_buf[params->prime_len]; - size_t public_len; - unsigned int zeros = 0; - uint8_t pre_master_secret[params->prime_len]; - size_t pre_master_secret_len; - - public_len = params->prime_len; - memset(public_buf, 0, sizeof(public_buf)); - - if (!l_key_compute_dh_public(params->generator, params->private, - params->prime, public_buf, - &public_len)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "l_key_compute_dh_public failed"); - return false; - } - - while (zeros < public_len && public_buf[zeros] == 0x00) - zeros++; - - l_put_be16(public_len - zeros, ptr); - memcpy(ptr + 2, public_buf + zeros, public_len - zeros); - ptr += 2 + public_len - zeros; - - pre_master_secret_len = params->prime_len; - zeros = 0; - - if (!l_key_compute_dh_secret(params->public, params->private, - params->prime, pre_master_secret, - &pre_master_secret_len)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Generating DH shared-secret failed"); - return false; - } - - while (zeros < pre_master_secret_len && - pre_master_secret[zeros] == 0x00) - zeros++; - - tls_tx_handshake(tls, TLS_CLIENT_KEY_EXCHANGE, buf, ptr - buf); - - tls_free_dhe_params(tls); - tls_generate_master_secret(tls, pre_master_secret + zeros, - pre_master_secret_len - zeros); - explicit_bzero(pre_master_secret, pre_master_secret_len); - return true; -} - -static void tls_handle_dhe_client_key_xchg(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - struct tls_dhe_params *params = tls->pending.key_xchg_params; - uint8_t pre_master_secret[params->prime_len]; - size_t pre_master_secret_len; - size_t public_len; - unsigned int zeros = 0; - - if (len < 2) - goto decode_error; - - public_len = l_get_be16(buf); - buf += 2; - len -= 2; - - if (public_len != len) - goto decode_error; - - /* - * RFC 7919 Section 4: - * "the server MUST verify that 1 < dh_Yc < dh_p - 1. If dh_Yc is - * out of range, the server MUST terminate the connection with - * a fatal handshake_failure(40) alert." - */ - if (!l_key_validate_dh_payload(buf, public_len, - tls->negotiated_ff_group->ff.prime, - params->prime_len)) { - TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, - "Client DH public value invalid"); - return; - } - - params->public = l_key_new(L_KEY_RAW, buf, public_len); - if (!params->public) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, "l_key_new failed"); - return; - } - - pre_master_secret_len = params->prime_len; - - if (!l_key_compute_dh_secret(params->public, params->private, - params->prime, pre_master_secret, - &pre_master_secret_len)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Generating DH shared-secret failed"); - return; - } - - while (zeros < pre_master_secret_len && - pre_master_secret[zeros] == 0x00) - zeros++; - - tls_free_dhe_params(tls); - tls_generate_master_secret(tls, pre_master_secret + zeros, - pre_master_secret_len - zeros); - explicit_bzero(pre_master_secret, pre_master_secret_len); - return; - -decode_error: - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "ClientKeyExchange decode error"); -} - -static struct tls_key_exchange_algorithm tls_dhe = { - .need_ecc = true, - .send_server_key_exchange = tls_send_dhe_server_key_xchg, - .handle_server_key_exchange = tls_handle_dhe_server_key_xchg, - .send_client_key_exchange = tls_send_dhe_client_key_xchg, - .handle_client_key_exchange = tls_handle_dhe_client_key_xchg, - .free_params = tls_free_dhe_params, -}; - -static struct tls_bulk_encryption_algorithm tls_rc4 = { - .cipher_type = TLS_CIPHER_STREAM, - .l_id = L_CIPHER_ARC4, - .key_length = 16, -}, tls_aes128 = { - .cipher_type = TLS_CIPHER_BLOCK, - .l_id = L_CIPHER_AES_CBC, - .key_length = 16, - .iv_length = 16, - .block_length = 16, -}, tls_aes256 = { - .cipher_type = TLS_CIPHER_BLOCK, - .l_id = L_CIPHER_AES_CBC, - .key_length = 32, - .iv_length = 16, - .block_length = 16, -}, tls_3des_ede = { - .cipher_type = TLS_CIPHER_BLOCK, - .l_id = L_CIPHER_DES3_EDE_CBC, - .key_length = 24, - .iv_length = 8, - .block_length = 8, -}, tls_aes128_gcm = { - .cipher_type = TLS_CIPHER_AEAD, - .l_aead_id = L_AEAD_CIPHER_AES_GCM, - .key_length = 16, - .iv_length = 12, - .fixed_iv_length = 4, - .auth_tag_length = 16, -}, tls_aes256_gcm = { - .cipher_type = TLS_CIPHER_AEAD, - .l_aead_id = L_AEAD_CIPHER_AES_GCM, - .key_length = 32, - .iv_length = 12, - .fixed_iv_length = 4, - .auth_tag_length = 16, -}; - -static struct tls_mac_algorithm tls_md5 = { - .id = 1, - .hmac_type = L_CHECKSUM_MD5, - .mac_length = 16, -}, tls_sha = { - .id = 2, - .hmac_type = L_CHECKSUM_SHA1, - .mac_length = 20, -}, tls_sha256 = { - .id = 4, - .hmac_type = L_CHECKSUM_SHA256, - .mac_length = 32, -}, tls_sha384 = { - .id = 5, - .hmac_type = L_CHECKSUM_SHA384, - .mac_length = 48, -}; - -static struct tls_cipher_suite tls_rsa_with_rc4_128_md5 = { - .id = { 0x00, 0x04 }, - .name = "TLS_RSA_WITH_RC4_128_MD5", - .verify_data_length = 12, - .encryption = &tls_rc4, - .mac = &tls_md5, - .signature = &tls_rsa_signature, - .key_xchg = &tls_rsa_key_xchg, -}, tls_rsa_with_rc4_128_sha = { - .id = { 0x00, 0x05 }, - .name = "TLS_RSA_WITH_RC4_128_SHA", - .verify_data_length = 12, - .encryption = &tls_rc4, - .mac = &tls_sha, - .signature = &tls_rsa_signature, - .key_xchg = &tls_rsa_key_xchg, -}, tls_rsa_with_3des_ede_cbc_sha = { - .id = { 0x00, 0x0a }, - .name = "TLS_RSA_WITH_3DES_EDE_CBC_SHA", - .verify_data_length = 12, - .encryption = &tls_3des_ede, - .mac = &tls_sha, - .signature = &tls_rsa_signature, - .key_xchg = &tls_rsa_key_xchg, -}, tls_dhe_rsa_with_3des_ede_cbc_sha = { - .id = { 0x00, 0x16 }, - .name = "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", - .verify_data_length = 12, - .encryption = &tls_3des_ede, - .mac = &tls_sha, - .signature = &tls_rsa_signature, - .key_xchg = &tls_dhe, -}, tls_rsa_with_aes_128_cbc_sha = { - .id = { 0x00, 0x2f }, - .name = "TLS_RSA_WITH_AES_128_CBC_SHA", - .verify_data_length = 12, - .encryption = &tls_aes128, - .mac = &tls_sha, - .signature = &tls_rsa_signature, - .key_xchg = &tls_rsa_key_xchg, -}, tls_dhe_rsa_with_aes_128_cbc_sha = { - .id = { 0x00, 0x33 }, - .name = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", - .verify_data_length = 12, - .encryption = &tls_aes128, - .mac = &tls_sha, - .signature = &tls_rsa_signature, - .key_xchg = &tls_dhe, -}, tls_rsa_with_aes_256_cbc_sha = { - .id = { 0x00, 0x35 }, - .name = "TLS_RSA_WITH_AES_256_CBC_SHA", - .verify_data_length = 12, - .encryption = &tls_aes256, - .mac = &tls_sha, - .signature = &tls_rsa_signature, - .key_xchg = &tls_rsa_key_xchg, -}, tls_dhe_rsa_with_aes_256_cbc_sha = { - .id = { 0x00, 0x39 }, - .name = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", - .verify_data_length = 12, - .encryption = &tls_aes256, - .mac = &tls_sha, - .signature = &tls_rsa_signature, - .key_xchg = &tls_dhe, -}, tls_rsa_with_aes_128_cbc_sha256 = { - .id = { 0x00, 0x3c }, - .name = "TLS_RSA_WITH_AES_128_CBC_SHA256", - .verify_data_length = 12, - .encryption = &tls_aes128, - .mac = &tls_sha256, - .signature = &tls_rsa_signature, - .key_xchg = &tls_rsa_key_xchg, -}, tls_rsa_with_aes_256_cbc_sha256 = { - .id = { 0x00, 0x3d }, - .name = "TLS_RSA_WITH_AES_256_CBC_SHA256", - .verify_data_length = 12, - .encryption = &tls_aes256, - .mac = &tls_sha256, - .signature = &tls_rsa_signature, - .key_xchg = &tls_rsa_key_xchg, -}, tls_dhe_rsa_with_aes_128_cbc_sha256 = { - .id = { 0x00, 0x67 }, - .name = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", - .verify_data_length = 12, - .encryption = &tls_aes128, - .mac = &tls_sha256, - .signature = &tls_rsa_signature, - .key_xchg = &tls_dhe, -}, tls_dhe_rsa_with_aes_256_cbc_sha256 = { - .id = { 0x00, 0x6b }, - .name = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", - .verify_data_length = 12, - .encryption = &tls_aes256, - .mac = &tls_sha256, - .signature = &tls_rsa_signature, - .key_xchg = &tls_dhe, -}, tls_rsa_with_aes_128_gcm_sha256 = { - .id = { 0x00, 0x9c }, - .name = "TLS_RSA_WITH_AES_128_GCM_SHA256", - .verify_data_length = 12, - .encryption = &tls_aes128_gcm, - .signature = &tls_rsa_signature, - .key_xchg = &tls_rsa_key_xchg, -}, tls_rsa_with_aes_256_gcm_sha384 = { - .id = { 0x00, 0x9d }, - .name = "TLS_RSA_WITH_AES_256_GCM_SHA384", - .verify_data_length = 12, - .encryption = &tls_aes256_gcm, - .prf_hmac = L_CHECKSUM_SHA384, - .signature = &tls_rsa_signature, - .key_xchg = &tls_rsa_key_xchg, -}, tls_dhe_rsa_with_aes_128_gcm_sha256 = { - .id = { 0x00, 0x9e }, - .name = "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", - .verify_data_length = 12, - .encryption = &tls_aes128_gcm, - .signature = &tls_rsa_signature, - .key_xchg = &tls_dhe, -}, tls_dhe_rsa_with_aes_256_gcm_sha384 = { - .id = { 0x00, 0x9f }, - .name = "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", - .verify_data_length = 12, - .encryption = &tls_aes256_gcm, - .prf_hmac = L_CHECKSUM_SHA384, - .signature = &tls_rsa_signature, - .key_xchg = &tls_dhe, -}, tls_ecdhe_rsa_with_rc4_128_sha = { - .id = { 0xc0, 0x11 }, - .name = "TLS_ECDHE_RSA_WITH_RC4_128_SHA", - .verify_data_length = 12, - .encryption = &tls_rc4, - .mac = &tls_sha, - .signature = &tls_rsa_signature, - .key_xchg = &tls_ecdhe, -}, tls_ecdhe_rsa_with_3des_ede_cbc_sha = { - .id = { 0xc0, 0x12 }, - .name = "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", - .verify_data_length = 12, - .encryption = &tls_3des_ede, - .mac = &tls_sha, - .signature = &tls_rsa_signature, - .key_xchg = &tls_ecdhe, -}, tls_ecdhe_rsa_with_aes_128_cbc_sha = { - .id = { 0xc0, 0x13 }, - .name = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - .verify_data_length = 12, - .encryption = &tls_aes128, - .mac = &tls_sha, - .signature = &tls_rsa_signature, - .key_xchg = &tls_ecdhe, -}, tls_ecdhe_rsa_with_aes_256_cbc_sha = { - .id = { 0xc0, 0x14 }, - .name = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - .verify_data_length = 12, - .encryption = &tls_aes256, - .mac = &tls_sha, - .signature = &tls_rsa_signature, - .key_xchg = &tls_ecdhe, -}, tls_ecdhe_rsa_with_aes_128_cbc_sha256 = { - .id = { 0xc0, 0x27 }, - .name = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", - .verify_data_length = 12, - .encryption = &tls_aes128, - .mac = &tls_sha256, - .signature = &tls_rsa_signature, - .key_xchg = &tls_ecdhe, -}, tls_ecdhe_rsa_with_aes_256_cbc_sha384 = { - .id = { 0xc0, 0x28 }, - .name = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", - .verify_data_length = 12, - .encryption = &tls_aes256, - .mac = &tls_sha384, - .prf_hmac = L_CHECKSUM_SHA384, - .signature = &tls_rsa_signature, - .key_xchg = &tls_ecdhe, -}, tls_ecdhe_rsa_with_aes_128_gcm_sha256 = { - .id = { 0xc0, 0x2f }, - .name = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - .verify_data_length = 12, - .encryption = &tls_aes128_gcm, - .signature = &tls_rsa_signature, - .key_xchg = &tls_ecdhe, -}, tls_ecdhe_rsa_with_aes_256_gcm_sha384 = { - .id = { 0xc0, 0x30 }, - .name = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - .verify_data_length = 12, - .encryption = &tls_aes256_gcm, - .prf_hmac = L_CHECKSUM_SHA384, - .signature = &tls_rsa_signature, - .key_xchg = &tls_ecdhe, -}; - -struct tls_cipher_suite *tls_cipher_suite_pref[] = { - &tls_ecdhe_rsa_with_aes_256_cbc_sha, - &tls_ecdhe_rsa_with_aes_128_cbc_sha, - &tls_dhe_rsa_with_aes_256_cbc_sha, - &tls_dhe_rsa_with_aes_128_cbc_sha, - &tls_rsa_with_aes_256_cbc_sha, - &tls_rsa_with_aes_128_cbc_sha, - &tls_ecdhe_rsa_with_aes_256_cbc_sha384, - &tls_ecdhe_rsa_with_aes_128_cbc_sha256, - &tls_dhe_rsa_with_aes_256_cbc_sha256, - &tls_dhe_rsa_with_aes_128_cbc_sha256, - &tls_rsa_with_aes_256_cbc_sha256, - &tls_rsa_with_aes_128_cbc_sha256, - &tls_ecdhe_rsa_with_aes_256_gcm_sha384, - &tls_ecdhe_rsa_with_aes_128_gcm_sha256, - &tls_dhe_rsa_with_aes_256_gcm_sha384, - &tls_dhe_rsa_with_aes_128_gcm_sha256, - &tls_rsa_with_aes_256_gcm_sha384, - &tls_rsa_with_aes_128_gcm_sha256, - &tls_ecdhe_rsa_with_3des_ede_cbc_sha, - &tls_dhe_rsa_with_3des_ede_cbc_sha, - &tls_rsa_with_3des_ede_cbc_sha, - &tls_ecdhe_rsa_with_rc4_128_sha, - &tls_rsa_with_rc4_128_sha, - &tls_rsa_with_rc4_128_md5, - NULL, -}; diff --git a/ell/tls.c b/ell/tls.c deleted file mode 100644 index 52e7924..0000000 --- a/ell/tls.c +++ /dev/null @@ -1,3078 +0,0 @@ -/* - * Embedded Linux library - * - * Copyright (C) 2015 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include -#include -#include -#include -#include - -#include "util.h" -#include "private.h" -#include "tls.h" -#include "checksum.h" -#include "cipher.h" -#include "random.h" -#include "queue.h" -#include "pem.h" -#include "cert.h" -#include "cert-private.h" -#include "tls-private.h" -#include "key.h" -#include "asn1-private.h" -#include "strv.h" -#include "missing.h" -#include "string.h" - -bool tls10_prf(const void *secret, size_t secret_len, - const char *label, - const void *seed, size_t seed_len, - uint8_t *out, size_t out_len) -{ - uint8_t p_hash2[out_len]; - uint8_t l_s1 = (secret_len + 1) / 2; - unsigned int i; - - /* - * RFC2246 section 5: - * S1 and S2 are the two halves of the secret, and each is the same - * length. S1 is taken from the first half of the secret, S2 from the - * second half. Their length is created by rounding up the length of - * the overall secret, divided by two; thus, if the original secret is - * an odd number of bytes long, the last byte of S1 will be the same as - * the first byte of S2. - */ - - if (!tls12_prf(L_CHECKSUM_MD5, secret, l_s1, - label, seed, seed_len, - out, out_len)) - return false; - - if (secret_len > 0) - secret += secret_len - l_s1; - - if (!tls12_prf(L_CHECKSUM_SHA1, secret, l_s1, - label, seed, seed_len, - p_hash2, out_len)) - return false; - - for (i = 0; i < out_len; i++) - out[i] ^= p_hash2[i]; - - return true; -} - -bool tls12_prf(enum l_checksum_type type, - const void *secret, size_t secret_len, - const char *label, - const void *seed, size_t seed_len, - uint8_t *out, size_t out_len) -{ - struct l_checksum *hmac = l_checksum_new_hmac(type, secret, secret_len); - size_t a_len, chunk_len, prfseed_len = strlen(label) + seed_len; - uint8_t a[64 + prfseed_len], prfseed[prfseed_len]; - - if (!hmac) - return false; - - /* Generate the hash seed or A(0) as label + seed */ - memcpy(prfseed, label, strlen(label)); - memcpy(prfseed + strlen(label), seed, seed_len); - - memcpy(a, prfseed, prfseed_len); - a_len = prfseed_len; - - while (out_len) { - /* Generate A(i) */ - l_checksum_reset(hmac); - l_checksum_update(hmac, a, a_len); - a_len = l_checksum_get_digest(hmac, a, sizeof(a)); - - /* Append seed & generate output */ - memcpy(a + a_len, prfseed, prfseed_len); - l_checksum_reset(hmac); - l_checksum_update(hmac, a, a_len + prfseed_len); - - chunk_len = l_checksum_get_digest(hmac, out, out_len); - out += chunk_len; - out_len -= chunk_len; - } - - l_checksum_free(hmac); - return true; -} - -static bool tls_prf_get_bytes(struct l_tls *tls, - const void *secret, size_t secret_len, - const char *label, - const void *seed, size_t seed_len, - uint8_t *buf, size_t len) -{ - if (tls->negotiated_version >= L_TLS_V12) - return tls12_prf(tls->prf_hmac->l_id, - secret, secret_len, label, - seed, seed_len, buf, len); - else - return tls10_prf(secret, secret_len, label, seed, seed_len, - buf, len); -} - -LIB_EXPORT bool l_tls_prf_get_bytes(struct l_tls *tls, bool use_master_secret, - const char *label, uint8_t *buf, size_t len) -{ - uint8_t seed[64]; - bool r; - - if (unlikely(!tls || !tls->prf_hmac)) - return false; - - memcpy(seed + 0, tls->pending.client_random, 32); - memcpy(seed + 32, tls->pending.server_random, 32); - - if (use_master_secret) - r = tls_prf_get_bytes(tls, tls->pending.master_secret, 48, - label, seed, 64, buf, len); - else - r = tls_prf_get_bytes(tls, "", 0, label, seed, 64, buf, len); - - explicit_bzero(seed, 64); - - return r; -} - -static void tls_write_random(uint8_t *buf) -{ - l_put_be32(time(NULL), buf); - - l_getrandom(buf + 4, 28); -} - -static void tls_drop_handshake_hash(struct l_tls *tls, - enum handshake_hash_type hash) -{ - if (tls->handshake_hash[hash]) { - l_checksum_free(tls->handshake_hash[hash]); - - tls->handshake_hash[hash] = NULL; - } -} - -static void tls_reset_handshake(struct l_tls *tls) -{ - enum handshake_hash_type hash; - - explicit_bzero(tls->pending.key_block, sizeof(tls->pending.key_block)); - - if (tls->pending.cipher_suite && - tls->pending.cipher_suite->key_xchg->free_params) - tls->pending.cipher_suite->key_xchg->free_params(tls); - - l_cert_free(tls->peer_cert); - l_key_free(tls->peer_pubkey); - - tls->peer_cert = NULL; - tls->peer_pubkey = NULL; - tls->peer_pubkey_size = 0; - tls->negotiated_curve = NULL; - tls->negotiated_ff_group = NULL; - - for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) - tls_drop_handshake_hash(tls, hash); - - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_START); - tls->cert_requested = 0; - tls->cert_sent = 0; -} - -static void tls_cleanup_handshake(struct l_tls *tls) -{ - explicit_bzero(tls->pending.client_random, 32); - explicit_bzero(tls->pending.server_random, 32); - explicit_bzero(tls->pending.master_secret, 48); -} - -static bool tls_change_cipher_spec(struct l_tls *tls, bool txrx, - const char **error) -{ - struct tls_bulk_encryption_algorithm *enc; - struct tls_mac_algorithm *mac; - int key_offset; - static char error_buf[200]; - - if (tls->cipher_type[txrx] == TLS_CIPHER_AEAD) { - if (tls->aead_cipher[txrx]) { - l_aead_cipher_free(tls->aead_cipher[txrx]); - tls->aead_cipher[txrx] = NULL; - } - } else { - if (tls->cipher[txrx]) { - l_cipher_free(tls->cipher[txrx]); - tls->cipher[txrx] = NULL; - } - } - - tls->cipher_type[txrx] = TLS_CIPHER_STREAM; - - if (tls->mac[txrx]) { - l_checksum_free(tls->mac[txrx]); - tls->mac[txrx] = NULL; - } - - tls->mac_length[txrx] = 0; - tls->block_length[txrx] = 0; - tls->record_iv_length[txrx] = 0; - - if (tls->fixed_iv_length[txrx]) { - explicit_bzero(tls->fixed_iv[txrx], tls->fixed_iv_length[txrx]); - tls->fixed_iv_length[txrx] = 0; - } - - tls->auth_tag_length[txrx] = 0; - tls->seq_num[txrx] = 0; - - tls->cipher_suite[txrx] = tls->pending.cipher_suite; - if (!tls->cipher_suite[txrx]) - return true; - - key_offset = 0; - - if (tls->cipher_suite[txrx]->mac) { - mac = tls->cipher_suite[txrx]->mac; - - /* Server write / client read is 2nd in the key block */ - if ((tls->server && txrx) || (!tls->server && !txrx)) - key_offset += mac->mac_length; - - tls->mac[txrx] = l_checksum_new_hmac(mac->hmac_type, - tls->pending.key_block + - key_offset, mac->mac_length); - - /* Wipe out the now unneeded part of the key block */ - explicit_bzero(tls->pending.key_block + key_offset, - mac->mac_length); - - if (!tls->mac[txrx]) { - if (error) { - *error = error_buf; - snprintf(error_buf, sizeof(error_buf), - "Can't create %s's %s HMAC", - tls->cipher_suite[txrx]->name, - txrx ? "Tx" : "Rx"); - } - - return false; - } - - tls->mac_length[txrx] = mac->mac_length; - - key_offset = 2 * mac->mac_length; - } - - if (tls->cipher_suite[txrx]->encryption) { - void *cipher; - - enc = tls->cipher_suite[txrx]->encryption; - - /* Server write / client read is 4th in the key block */ - if ((tls->server && txrx) || (!tls->server && !txrx)) - key_offset += enc->key_length; - - if (enc->cipher_type == TLS_CIPHER_AEAD) { - cipher = l_aead_cipher_new(enc->l_aead_id, - tls->pending.key_block + - key_offset, enc->key_length, - enc->auth_tag_length); - tls->aead_cipher[txrx] = cipher; - } else { - cipher = l_cipher_new(enc->l_id, - tls->pending.key_block + - key_offset, enc->key_length); - tls->cipher[txrx] = cipher; - } - - /* Wipe out the now unneeded part of the key block */ - explicit_bzero(tls->pending.key_block + key_offset, - enc->key_length); - - if (!cipher) { - if (error) { - *error = error_buf; - snprintf(error_buf, sizeof(error_buf), - "Can't create %s's %s cipher", - tls->cipher_suite[txrx]->name, - txrx ? "Tx" : "Rx"); - } - - return false; - } - - tls->cipher_type[txrx] = enc->cipher_type; - tls->record_iv_length[txrx] = enc->iv_length - - enc->fixed_iv_length; - tls->block_length[txrx] = enc->block_length; - tls->auth_tag_length[txrx] = enc->auth_tag_length; - - if ((tls->server && txrx) || (!tls->server && !txrx)) - key_offset += enc->key_length; - else - key_offset += 2 * enc->key_length; - } - - if (tls->negotiated_version <= L_TLS_V10 && - tls->cipher_suite[txrx]->encryption && - tls->cipher_suite[txrx]->encryption->cipher_type == - TLS_CIPHER_BLOCK) { - enc = tls->cipher_suite[txrx]->encryption; - - /* Server write / client read is 6th in the key block */ - if ((tls->server && txrx) || (!tls->server && !txrx)) - key_offset += enc->iv_length; - - l_cipher_set_iv(tls->cipher[txrx], tls->pending.key_block + - key_offset, enc->iv_length); - - /* Wipe out the now unneeded part of the key block */ - explicit_bzero(tls->pending.key_block + key_offset, - enc->iv_length); - } else if (tls->cipher_suite[txrx]->encryption && - tls->cipher_suite[txrx]->encryption->fixed_iv_length) { - enc = tls->cipher_suite[txrx]->encryption; - - /* Server write / client read is 6th in the key block */ - if ((tls->server && txrx) || (!tls->server && !txrx)) - key_offset += enc->fixed_iv_length; - - tls->fixed_iv_length[txrx] = enc->fixed_iv_length; - memcpy(tls->fixed_iv[txrx], tls->pending.key_block + key_offset, - enc->fixed_iv_length); - - /* Wipe out the now unneeded part of the key block */ - explicit_bzero(tls->pending.key_block + key_offset, - enc->fixed_iv_length); - } - - return true; -} - -static void tls_reset_cipher_spec(struct l_tls *tls, bool txrx) -{ - /* Reset everything to the TLS_NULL_WITH_NULL_NULL state */ - - tls->pending.cipher_suite = NULL; - - tls_change_cipher_spec(tls, txrx, NULL); -} - -bool tls_cipher_suite_is_compatible(struct l_tls *tls, - const struct tls_cipher_suite *suite, - const char **error) -{ - static char error_buf[200]; - struct l_cert *leaf; - enum l_tls_version min_version = - tls->negotiated_version ?: tls->min_version; - enum l_tls_version max_version = - tls->negotiated_version ?: tls->max_version; - - if (suite->encryption && - suite->encryption->cipher_type == TLS_CIPHER_AEAD) { - if (max_version < L_TLS_V12) { - if (error) { - *error = error_buf; - snprintf(error_buf, sizeof(error_buf), - "Cipher suite %s uses an AEAD " - "cipher (TLS 1.2+) but " - TLS_VER_FMT - " was negotiated or is the max " - "version allowed", suite->name, - TLS_VER_ARGS(tls->max_version)); - } - - return false; - } - - if (!l_aead_cipher_is_supported(suite->encryption->l_aead_id)) { - if (error) { - *error = error_buf; - snprintf(error_buf, sizeof(error_buf), - "Cipher suite %s's AEAD cipher " - "algorithm not supported by " - "the kernel", suite->name); - } - - return false; - } - } else if (suite->encryption) { /* Block or stream cipher */ - if (!l_cipher_is_supported(suite->encryption->l_id)) { - if (error) { - *error = error_buf; - snprintf(error_buf, sizeof(error_buf), - "Cipher suite %s's block/stream" - " cipher algorithm not " - "supported by the kernel", - suite->name); - } - - return false; - } - } - - if (suite->mac && - !l_checksum_is_supported(suite->mac->hmac_type, true)) { - if (error) { - *error = error_buf; - snprintf(error_buf, sizeof(error_buf), - "Cipher suite %s's HMAC algorithm not " - "supported by the kernel", suite->name); - } - - return false; - } - - if ( - (max_version < L_TLS_V12 && - (!l_checksum_is_supported(L_CHECKSUM_MD5, true) || - !l_checksum_is_supported(L_CHECKSUM_SHA1, true))) || - (min_version >= L_TLS_V12 && - !l_checksum_is_supported( - suite->prf_hmac != L_CHECKSUM_NONE ? - suite->prf_hmac : L_CHECKSUM_SHA256, - true))) { - if (error) { - *error = error_buf; - snprintf(error_buf, sizeof(error_buf), - "Cipher suite %s's PRF algorithm not " - "supported by the kernel", suite->name); - } - - return false; - } - - if (suite->key_xchg->need_ffdh && - !l_key_is_supported(L_KEY_FEATURE_DH)) { - if (error) { - *error = error_buf; - snprintf(error_buf, sizeof(error_buf), - "Cipher suite %s's key exchange " - "mechanism needs kernel DH support", - suite->name); - } - - return false; - } - - /* - * If the certificate is compatible with the signature algorithm it - * also must be compatible with the key exchange mechanism because - * the cipher suites are defined so that the same certificates can - * be used by both. - */ - leaf = l_certchain_get_leaf(tls->cert); - if (leaf && suite->signature && - !suite->signature->validate_cert_key_type(leaf)) { - if (error) { - *error = error_buf; - snprintf(error_buf, sizeof(error_buf), - "Local certificate has key type " - "incompatible with cipher suite %s's " - "signature algorithm", suite->name); - } - - return false; - } - - /* - * On the server we know what elliptic curve we'll be using as soon - * as we've processed the ClientHello so for EC-based key exchange - * methods require that a curve has been selected. - */ - if (suite->key_xchg->need_ecc && tls->server && - !tls->negotiated_curve) { - if (error) { - *error = error_buf; - snprintf(error_buf, sizeof(error_buf), - "No common supported elliptic curves " - "with the client, can't use %s", - suite->name); - } - - return false; - } - - /* Similarly for FF DH groups */ - if (suite->key_xchg->need_ffdh && tls->server && - !tls->negotiated_ff_group) { - if (error) { - *error = error_buf; - snprintf(error_buf, sizeof(error_buf), - "No common supported finite-field " - "groups with the client, can't use %s", - suite->name); - } - - return false; - } - - return true; -} - -static struct tls_cipher_suite *tls_find_cipher_suite(const uint8_t *id) -{ - struct tls_cipher_suite **suite; - - for (suite = tls_cipher_suite_pref; *suite; suite++) - if ((*suite)->id[0] == id[0] && (*suite)->id[1] == id[1]) - return *suite; - - return NULL; -} - -static struct tls_compression_method tls_compression_pref[] = { - { - 0, - "CompressionMethod.null", - }, -}; - -static struct tls_compression_method *tls_find_compression_method( - const uint8_t id) -{ - int i; - - for (i = 0; i < (int) L_ARRAY_SIZE(tls_compression_pref); i++) - if (tls_compression_pref[i].id == id) - return &tls_compression_pref[i]; - - return NULL; -} - -const struct tls_hash_algorithm tls_handshake_hash_data[] = { - [HANDSHAKE_HASH_SHA384] = { 5, L_CHECKSUM_SHA384, "SHA384" }, - [HANDSHAKE_HASH_SHA256] = { 4, L_CHECKSUM_SHA256, "SHA256" }, - [HANDSHAKE_HASH_MD5] = { 1, L_CHECKSUM_MD5, "MD5" }, - [HANDSHAKE_HASH_SHA1] = { 2, L_CHECKSUM_SHA1, "SHA1" }, -}; - -static bool tls_init_handshake_hash(struct l_tls *tls) -{ - enum handshake_hash_type hash; - bool tls10 = tls->max_version < L_TLS_V12; - - for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) { - /* Skip hash types we already know we won't need */ - if (tls10 && hash != HANDSHAKE_HASH_SHA1 && - hash != HANDSHAKE_HASH_MD5) - continue; - - if (tls->handshake_hash[hash]) { - TLS_DEBUG("Handshake hash %s already exists", - tls_handshake_hash_data[hash].name); - goto err; - } - - tls->handshake_hash[hash] = l_checksum_new( - tls_handshake_hash_data[hash].l_id); - - if (!tls->handshake_hash[hash]) { - TLS_DEBUG("Can't create %s hash", - tls_handshake_hash_data[hash].name); - goto err; - } - } - - return true; -err: - for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) - tls_drop_handshake_hash(tls, hash); - - return false; -} - -static const struct tls_hash_algorithm *tls_set_prf_hmac(struct l_tls *tls) -{ - enum handshake_hash_type hash; - - if (tls->pending.cipher_suite->prf_hmac == L_CHECKSUM_NONE) { - tls->prf_hmac = &tls_handshake_hash_data[HANDSHAKE_HASH_SHA256]; - return tls->prf_hmac; - } - - for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) - if (tls_handshake_hash_data[hash].l_id == - tls->pending.cipher_suite->prf_hmac) { - tls->prf_hmac = &tls_handshake_hash_data[hash]; - return tls->prf_hmac; - } - - return NULL; -} - -static bool tls_domain_match_mask(const char *name, size_t name_len, - const char *mask, size_t mask_len) -{ - bool at_start = true; - - while (1) { - const char *name_seg_end = memchr(name, '.', name_len); - const char *mask_seg_end = memchr(mask, '.', mask_len); - size_t name_seg_len = name_seg_end ? - (size_t) (name_seg_end - name) : name_len; - size_t mask_seg_len = mask_seg_end ? - (size_t) (mask_seg_end - mask) : mask_len; - - if (mask_seg_len == 1 && mask[0] == '*') { - /* - * A * at the beginning of the mask matches any - * number of labels. - */ - if (at_start && name_seg_end && - tls_domain_match_mask(name_seg_end + 1, - name_len - name_seg_len - 1, - mask, mask_len)) - return true; - - goto ok_next; - } - - if (name_seg_len != mask_seg_len || - memcmp(name, mask, name_seg_len)) - return false; - -ok_next: - /* If either string ends here both must end here */ - if (!name_seg_end || !mask_seg_end) - return !name_seg_end && !mask_seg_end; - - at_start = false; - name = name_seg_end + 1; - name_len -= name_seg_len + 1; - mask = mask_seg_end + 1; - mask_len -= mask_seg_len + 1; - } -} - -static const struct asn1_oid subject_alt_name_oid = - { 3, { 0x55, 0x1d, 0x11 } }; -static const struct asn1_oid dn_common_name_oid = - { 3, { 0x55, 0x04, 0x03 } }; - -#define SAN_DNS_NAME_ID ASN1_CONTEXT_IMPLICIT(2) - -static bool tls_cert_domains_match_mask(struct l_cert *cert, char **mask) -{ - const uint8_t *san, *dn, *end; - size_t san_len, dn_len; - uint8_t san_tag; - const char *cn = NULL; - size_t cn_len; - char **i; - bool dns_name_present = false; - - /* - * Locate SubjectAltName (RFC5280 Section 4.2.1.6) and descend into - * the sole SEQUENCE element, check if any DNSName matches. - */ - san = cert_get_extension(cert, &subject_alt_name_oid, NULL, &san_len); - if (san) { - san = asn1_der_find_elem(san, san_len, 0, &san_tag, &san_len); - if (unlikely(!san || san_tag != ASN1_ID_SEQUENCE)) - return false; - - end = san + san_len; - while (san < end) { - const uint8_t *value; - uint8_t tag; - size_t len; - - value = asn1_der_find_elem(san, end - san, - SAN_DNS_NAME_ID, - &tag, &len); - if (!value) - break; - - /* Type is implicitly IA5STRING */ - - for (i = mask; *i; i++) - if (tls_domain_match_mask((const char *) value, - len, *i, strlen(*i))) - return true; - - san = value + len; - dns_name_present = true; - } - } - - /* - * Retrieve the Common Name from the Subject DN and check if it - * matches. - * - * We look at the Common Name only if no DNSNames were present in - * the certificate, following Wi-Fi Alliance's Hotspot 2.0 - * Specification v3.1 section 7.3.3.2 step 2: - * "Verify in the AAA server certificate that the domain name from - * the FQDN [...] is a suffix match of the domain name in at least - * one of the DNSName SubjectAltName extensions. If a SubjectAltName - * of type DNSName is not present, then the domain name from the - * FQDN shall be a suffix match to the CommonName portion of the - * SubjectName. If neither of these conditions holds, then - * verification fails." - */ - if (unlikely(dns_name_present)) - return false; - - dn = l_cert_get_dn(cert, &dn_len); - if (unlikely(!dn)) - return false; - - end = dn + dn_len; - while (dn < end) { - const uint8_t *set, *seq, *oid, *name; - uint8_t tag; - size_t len, oid_len, name_len; - - set = asn1_der_find_elem(dn, end - dn, 0, &tag, &len); - if (unlikely(!set || tag != ASN1_ID_SET)) - return false; - - dn = set + len; - - seq = asn1_der_find_elem(set, len, 0, &tag, &len); - if (unlikely(!seq || tag != ASN1_ID_SEQUENCE)) - return false; - - oid = asn1_der_find_elem(seq, len, 0, &tag, &oid_len); - if (unlikely(!oid || tag != ASN1_ID_OID)) - return false; - - name = asn1_der_find_elem(seq, len, 1, &tag, &name_len); - if (unlikely(!name || (tag != ASN1_ID_PRINTABLESTRING && - tag != ASN1_ID_UTF8STRING && - tag != ASN1_ID_IA5STRING))) - continue; - - if (asn1_oid_eq(&dn_common_name_oid, oid_len, oid)) { - cn = (const char *) name; - cn_len = name_len; - break; - } - } - - if (unlikely(!cn)) - return false; - - for (i = mask; *i; i++) - if (tls_domain_match_mask(cn, cn_len, *i, strlen(*i))) - return true; - - return false; -} - -#define SWITCH_ENUM_TO_STR(val) \ - case (val): \ - return L_STRINGIFY(val); - -static const char *tls_handshake_type_to_str(enum tls_handshake_type type) -{ - static char buf[100]; - - switch (type) { - SWITCH_ENUM_TO_STR(TLS_HELLO_REQUEST) - SWITCH_ENUM_TO_STR(TLS_CLIENT_HELLO) - SWITCH_ENUM_TO_STR(TLS_SERVER_HELLO) - SWITCH_ENUM_TO_STR(TLS_CERTIFICATE) - SWITCH_ENUM_TO_STR(TLS_SERVER_KEY_EXCHANGE) - SWITCH_ENUM_TO_STR(TLS_CERTIFICATE_REQUEST) - SWITCH_ENUM_TO_STR(TLS_SERVER_HELLO_DONE) - SWITCH_ENUM_TO_STR(TLS_CERTIFICATE_VERIFY) - SWITCH_ENUM_TO_STR(TLS_CLIENT_KEY_EXCHANGE) - SWITCH_ENUM_TO_STR(TLS_FINISHED) - } - - snprintf(buf, sizeof(buf), "tls_handshake_type(%i)", type); - return buf; -} - -static void tls_send_alert(struct l_tls *tls, bool fatal, - enum l_tls_alert_desc alert_desc) -{ - uint8_t buf[2]; - - TLS_DEBUG("Sending a %s Alert: %s", fatal ? "Fatal" : "Warning", - l_tls_alert_to_str(alert_desc)); - - buf[0] = fatal ? 2 : 1; - buf[1] = alert_desc; - - tls_tx_record(tls, TLS_CT_ALERT, buf, 2); -} - -/* - * Callers make sure this is about the last function before returning - * from the stack frames up to the exported library call so that the - * user-supplied disconnected callback here is free to use l_tls_free - * for example. - */ -void tls_disconnect(struct l_tls *tls, enum l_tls_alert_desc desc, - enum l_tls_alert_desc local_desc) -{ - tls_send_alert(tls, true, desc); - - tls_reset_handshake(tls); - tls_cleanup_handshake(tls); - - tls_reset_cipher_spec(tls, 0); - tls_reset_cipher_spec(tls, 1); - - tls->negotiated_version = 0; - tls->ready = false; - - tls->disconnected(local_desc ?: desc, local_desc && !desc, - tls->user_data); -} - -void tls_tx_handshake(struct l_tls *tls, int type, uint8_t *buf, size_t length) -{ - int i; - - TLS_DEBUG("Sending a %s of %zi bytes", - tls_handshake_type_to_str(type), - length - TLS_HANDSHAKE_HEADER_SIZE); - - /* Fill in the handshake header */ - - buf[0] = type; - buf[1] = (length - TLS_HANDSHAKE_HEADER_SIZE) >> 16; - buf[2] = (length - TLS_HANDSHAKE_HEADER_SIZE) >> 8; - buf[3] = (length - TLS_HANDSHAKE_HEADER_SIZE) >> 0; - - for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++) - if (tls->handshake_hash[i]) - l_checksum_update(tls->handshake_hash[i], buf, length); - - tls_tx_record(tls, TLS_CT_HANDSHAKE, buf, length); -} - -static ssize_t tls_append_hello_extensions(struct l_tls *tls, - struct l_queue *extensions, - uint8_t *buf, size_t len) -{ - uint8_t *ptr = buf; - uint8_t *extensions_len_ptr = ptr; - bool client_hello = !tls->server; - unsigned int i = 0; - const struct l_queue_entry *entry = l_queue_get_entries(extensions); - - if (len < 2) - return -ENOSPC; - - ptr += 2; - len -= 2; - - while (1) { - const struct tls_hello_extension *extension; - ssize_t ext_len; - ssize_t (*ext_write)(struct l_tls *tls, - uint8_t *buf, size_t len); - - if (client_hello) { - extension = &tls_extensions[i++]; - if (!extension->name) - break; - - ext_write = extension->client_write; - } else { - uint16_t ext_id; - - if (!entry) - break; - - ext_id = L_PTR_TO_UINT(entry->data); - entry = entry->next; - - for (i = 0; tls_extensions[i].name; i++) - if (tls_extensions[i].id == ext_id) - break; - - extension = &tls_extensions[i]; - if (!extension->name) - continue; - - ext_write = extension->server_write; - } - - /* - * Note: could handle NULL client_write with non-NULL - * server_handle or server_handle_absent as "server-oriented" - * extension (7.4.1.4) and write empty extension_data and - * simliarly require empty extension_data in - * tls_handle_client_hello if client_handle NULL. - */ - if (!ext_write) - continue; - - if (len < 4) - return -ENOSPC; - - ext_len = ext_write(tls, ptr + 4, len - 4); - if (ext_len == -ENOMSG) - continue; - - if (ext_len < 0) { - TLS_DEBUG("%s extension's %s_write: %s", - extension->name, - client_hello ? "client" : "server", - strerror(-ext_len)); - return ext_len; - } - - l_put_be16(extension->id, ptr + 0); - l_put_be16(ext_len, ptr + 2); - ptr += 4 + ext_len; - len -= 4 + ext_len; - } - - if (ptr > extensions_len_ptr + 2) - l_put_be16(ptr - (extensions_len_ptr + 2), extensions_len_ptr); - else /* Skip the length if no extensions */ - ptr = extensions_len_ptr; - - return ptr - buf; -} - -static bool tls_send_client_hello(struct l_tls *tls) -{ - uint8_t buf[1024 + L_ARRAY_SIZE(tls_compression_pref)]; - uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; - uint8_t *len_ptr; - unsigned int i; - ssize_t r; - struct tls_cipher_suite **suite; - - /* Fill in the Client Hello body */ - - *ptr++ = (uint8_t) (tls->max_version >> 8); - *ptr++ = (uint8_t) (tls->max_version >> 0); - - tls_write_random(tls->pending.client_random); - memcpy(ptr, tls->pending.client_random, 32); - ptr += 32; - - *ptr++ = 0; /* No SessionID */ - - len_ptr = ptr; - ptr += 2; - - for (suite = tls->cipher_suite_pref_list; *suite; suite++) { - const char *error; - - if (!tls_cipher_suite_is_compatible(tls, *suite, &error)) { - TLS_DEBUG("non-fatal: %s", error); - continue; - } - - *ptr++ = (*suite)->id[0]; - *ptr++ = (*suite)->id[1]; - } - - if (ptr == len_ptr + 2) { - TLS_DEBUG("No compatible cipher suites, check kernel config, " - "certificate's key type and TLS version range"); - return false; - } - - l_put_be16((ptr - len_ptr - 2), len_ptr); - *ptr++ = L_ARRAY_SIZE(tls_compression_pref); - - for (i = 0; i < L_ARRAY_SIZE(tls_compression_pref); i++) - *ptr++ = tls_compression_pref[i].id; - - r = tls_append_hello_extensions(tls, NULL, - ptr, buf + sizeof(buf) - ptr); - if (r < 0) - return false; - - ptr += r; - - tls_tx_handshake(tls, TLS_CLIENT_HELLO, buf, ptr - buf); - return true; -} - -static bool tls_send_server_hello(struct l_tls *tls, struct l_queue *extensions) -{ - uint8_t buf[1024]; - uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; - ssize_t r; - - /* Fill in the Server Hello body */ - - *ptr++ = tls->negotiated_version >> 8; - *ptr++ = tls->negotiated_version >> 0; - - tls_write_random(tls->pending.server_random); - memcpy(ptr, tls->pending.server_random, 32); - ptr += 32; - - *ptr++ = 0; /* Sessions are not cached */ - - *ptr++ = tls->pending.cipher_suite->id[0]; - *ptr++ = tls->pending.cipher_suite->id[1]; - - *ptr++ = tls->pending.compression_method->id; - - r = tls_append_hello_extensions(tls, extensions, - ptr, buf + sizeof(buf) - ptr); - if (r < 0) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Error appending extensions: %s", - strerror(-r)); - return false; - } - - ptr += r; - - tls_tx_handshake(tls, TLS_SERVER_HELLO, buf, ptr - buf); - return true; -} - -static bool tls_cert_list_add_size(struct l_cert *cert, void *user_data) -{ - size_t *total = user_data; - size_t der_len; - - l_cert_get_der_data(cert, &der_len); - *total += 3 + der_len; - - return false; -} - -static bool tls_cert_list_append(struct l_cert *cert, void *user_data) -{ - uint8_t **ptr = user_data; - const uint8_t *der; - size_t der_len; - - der = l_cert_get_der_data(cert, &der_len); - *(*ptr)++ = der_len >> 16; - *(*ptr)++ = der_len >> 8; - *(*ptr)++ = der_len >> 0; - memcpy(*ptr, der, der_len); - *ptr += der_len; - - return false; -} - -static bool tls_send_certificate(struct l_tls *tls) -{ - uint8_t *buf, *ptr; - size_t total; - - if (tls->server && !tls->cert) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, TLS_ALERT_BAD_CERT, - "Certificate needed in server mode"); - return false; - } - - /* - * TODO: check that the certificate is compatible with hash and - * signature algorithms lists supplied to us in the Client Hello - * extensions (if we're a 1.2+ server) or in the Certificate Request - * (if we act as a 1.2+ client). - * - * - for the hash and signature_algorithms list, check all - * certs in the cert chain. - * - * - also if !cipher_suite->key_xchg->key_exchange_msg, check that the - * end entity certificate's key type matches and is usable with some - * hash/signature pair. - * - * - on client check if any of the supplied DNs (if any) match - * anything in our cert chain. - */ - - total = 0; - l_certchain_walk_from_leaf(tls->cert, tls_cert_list_add_size, &total); - - buf = l_malloc(128 + total); - ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; - - /* Fill in the Certificate body */ - - *ptr++ = total >> 16; - *ptr++ = total >> 8; - *ptr++ = total >> 0; - l_certchain_walk_from_leaf(tls->cert, tls_cert_list_append, &ptr); - - tls_tx_handshake(tls, TLS_CERTIFICATE, buf, ptr - buf); - - l_free(buf); - - if (tls->cert) - tls->cert_sent = true; - - return true; -} - -/* - * Note: ClientCertificateType.rsa_sign value coincides with the - * SignatureAlgorithm.rsa value but other values in those enum are - * different so we don't mix them, can't extract them from - * tls->pending.cipher_suite->signature. - */ -static uint8_t tls_cert_type_pref[] = { - 1, /* RSA_sign */ -}; - -static bool tls_send_certificate_request(struct l_tls *tls) -{ - uint8_t *buf, *ptr, *dn_ptr; - size_t len; - const struct l_queue_entry *entry; - unsigned int i; - size_t dn_total = 0; - - for (entry = l_queue_get_entries(tls->ca_certs); entry; - entry = entry->next) { - struct l_cert *ca_cert = entry->data; - size_t dn_size; - - if (l_cert_get_dn(ca_cert, &dn_size)) - dn_total += 10 + dn_size; - } - - len = 256 + L_ARRAY_SIZE(tls_cert_type_pref) + dn_total; - buf = l_malloc(len); - ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; - - /* Fill in the Certificate Request body */ - - *ptr++ = L_ARRAY_SIZE(tls_cert_type_pref); - for (i = 0; i < L_ARRAY_SIZE(tls_cert_type_pref); i++) - *ptr++ = tls_cert_type_pref[i]; - - if (tls->negotiated_version >= L_TLS_V12) { - ssize_t ret = tls_write_signature_algorithms(tls, ptr, - buf + len - ptr); - - if (ret < 0) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "tls_write_signature_algorithms: %s", - strerror(-ret)); - l_free(buf); - return false; - } - - ptr += ret; - } - - dn_ptr = ptr; - ptr += 2; /* Leave space for the total DN size */ - - for (entry = l_queue_get_entries(tls->ca_certs); entry; - entry = entry->next) { - struct l_cert *ca_cert = entry->data; - size_t dn_size; - const uint8_t *dn = l_cert_get_dn(ca_cert, &dn_size); - uint8_t *cur_dn_ptr = ptr; - - if (!dn) - continue; - - ptr += 2; /* Leave space for current DN size */ - *ptr++ = ASN1_ID_SEQUENCE; /* DER outer SEQUENCE tag */ - asn1_write_definite_length(&ptr, dn_size); /* length */ - memcpy(ptr, dn, dn_size); /* value */ - ptr += dn_size; - l_put_be16(ptr - cur_dn_ptr - 2, cur_dn_ptr); - } - - l_put_be16(ptr - dn_ptr - 2, dn_ptr); /* DistinguishedNames size */ - - tls_tx_handshake(tls, TLS_CERTIFICATE_REQUEST, buf, ptr - buf); - - l_free(buf); - - return true; -} - -static void tls_send_server_hello_done(struct l_tls *tls) -{ - uint8_t buf[32]; - - /* No body */ - - tls_tx_handshake(tls, TLS_SERVER_HELLO_DONE, buf, - TLS_HANDSHAKE_HEADER_SIZE); -} - -void tls_generate_master_secret(struct l_tls *tls, - const uint8_t *pre_master_secret, - int pre_master_secret_len) -{ - uint8_t seed[64]; - int key_block_size; - - memcpy(seed + 0, tls->pending.client_random, 32); - memcpy(seed + 32, tls->pending.server_random, 32); - - tls_prf_get_bytes(tls, pre_master_secret, pre_master_secret_len, - "master secret", seed, 64, - tls->pending.master_secret, 48); - - /* Directly generate the key block while we're at it */ - key_block_size = 0; - - if (tls->pending.cipher_suite->encryption) - key_block_size += 2 * - tls->pending.cipher_suite->encryption->key_length; - - if (tls->pending.cipher_suite->mac) - key_block_size += 2 * - tls->pending.cipher_suite->mac->mac_length; - - if (tls->pending.cipher_suite->encryption && - tls->negotiated_version <= L_TLS_V10 && - tls->pending.cipher_suite->encryption->cipher_type == - TLS_CIPHER_BLOCK) - key_block_size += 2 * - tls->pending.cipher_suite->encryption->iv_length; - - if (tls->pending.cipher_suite->encryption) - key_block_size += 2 * tls->pending.cipher_suite->encryption-> - fixed_iv_length; - - /* Reverse order from the master secret seed */ - memcpy(seed + 0, tls->pending.server_random, 32); - memcpy(seed + 32, tls->pending.client_random, 32); - - tls_prf_get_bytes(tls, tls->pending.master_secret, 48, - "key expansion", seed, 64, - tls->pending.key_block, key_block_size); - - explicit_bzero(seed, 64); -} - -static void tls_get_handshake_hash(struct l_tls *tls, - enum handshake_hash_type type, - uint8_t *out) -{ - struct l_checksum *hash = l_checksum_clone(tls->handshake_hash[type]); - - if (!hash) - return; - - l_checksum_get_digest(hash, out, l_checksum_digest_length( - tls_handshake_hash_data[type].l_id)); - l_checksum_free(hash); -} - -static bool tls_get_handshake_hash_by_type(struct l_tls *tls, - enum handshake_hash_type type, - const uint8_t *data, size_t data_len, - uint8_t *out, size_t *out_len) -{ - if (!tls->handshake_hash[type]) - return false; - - if (out_len) - *out_len = l_checksum_digest_length( - tls_handshake_hash_data[type].l_id); - - tls_get_handshake_hash(tls, type, out); - return true; -} - -static bool tls_send_certificate_verify(struct l_tls *tls) -{ - uint8_t buf[2048]; - int i; - ssize_t sign_len; - - /* Fill in the Certificate Verify body */ - - sign_len = tls->pending.cipher_suite->signature->sign(tls, - buf + TLS_HANDSHAKE_HEADER_SIZE, - 2048 - TLS_HANDSHAKE_HEADER_SIZE, - tls_get_handshake_hash_by_type, - NULL, 0); - - if (sign_len < 0) - return false; - - /* Stop maintaining handshake message hashes other than the PRF hash */ - if (tls->negotiated_version >= L_TLS_V12) - for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++) - if (&tls_handshake_hash_data[i] != tls->prf_hmac) - tls_drop_handshake_hash(tls, i); - - tls_tx_handshake(tls, TLS_CERTIFICATE_VERIFY, buf, - sign_len + TLS_HANDSHAKE_HEADER_SIZE); - - return true; -} - -static void tls_send_change_cipher_spec(struct l_tls *tls) -{ - uint8_t buf = 1; - - tls_tx_record(tls, TLS_CT_CHANGE_CIPHER_SPEC, &buf, 1); -} - -static void tls_send_finished(struct l_tls *tls) -{ - uint8_t buf[512]; - uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; - uint8_t seed[HANDSHAKE_HASH_MAX_SIZE * 2]; - size_t seed_len; - - if (tls->negotiated_version >= L_TLS_V12) { - /* Same hash type as that used for the PRF (usually SHA256) */ - enum handshake_hash_type hash; - - for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) - if (&tls_handshake_hash_data[hash] == tls->prf_hmac) - break; - - tls_get_handshake_hash(tls, hash, seed); - seed_len = l_checksum_digest_length(tls->prf_hmac->l_id); - } else { - tls_get_handshake_hash(tls, HANDSHAKE_HASH_MD5, seed + 0); - tls_get_handshake_hash(tls, HANDSHAKE_HASH_SHA1, seed + 16); - seed_len = 36; - } - - tls_prf_get_bytes(tls, tls->pending.master_secret, 48, - tls->server ? "server finished" : - "client finished", - seed, seed_len, - ptr, tls->cipher_suite[1]->verify_data_length); - ptr += tls->cipher_suite[1]->verify_data_length; - - tls_tx_handshake(tls, TLS_FINISHED, buf, ptr - buf); -} - -static bool tls_verify_finished(struct l_tls *tls, const uint8_t *received, - size_t len) -{ - uint8_t expected[tls->cipher_suite[0]->verify_data_length]; - uint8_t *seed; - size_t seed_len; - - if (len != (size_t) tls->cipher_suite[0]->verify_data_length) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "TLS_FINISHED length not %i", - tls->cipher_suite[0]->verify_data_length); - - return false; - } - - if (tls->negotiated_version >= L_TLS_V12) { - enum handshake_hash_type hash; - - for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) - if (&tls_handshake_hash_data[hash] == tls->prf_hmac) - break; - - seed = tls->prev_digest[hash]; - seed_len = l_checksum_digest_length(tls->prf_hmac->l_id); - } else { - seed = alloca(36); - memcpy(seed + 0, tls->prev_digest[HANDSHAKE_HASH_MD5], 16); - memcpy(seed + 16, tls->prev_digest[HANDSHAKE_HASH_SHA1], 20); - seed_len = 36; - } - - tls_prf_get_bytes(tls, tls->pending.master_secret, 48, - tls->server ? "client finished" : - "server finished", - seed, seed_len, - expected, - tls->cipher_suite[0]->verify_data_length); - - if (memcmp(received, expected, len)) { - TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0, - "TLS_FINISHED contents don't match"); - - return false; - } - - return true; -} - -static bool tls_ptr_match(const void *a, const void *b) -{ - return a == b; -} - -static bool tls_handle_hello_extensions(struct l_tls *tls, - const uint8_t *buf, size_t len, - struct l_queue *seen) -{ - unsigned int i; - const struct tls_hello_extension *extension; - bool client_hello = tls->server; - uint16_t extensions_size; - - if (!len) - return true; - - if (len < 2 || len > 2 + 65535) - goto decode_error; - - extensions_size = l_get_be16(buf); - len -= 2; - buf += 2; - - if (len != extensions_size) - goto decode_error; - - while (len) { - uint16_t ext_id; - size_t ext_len; - bool (*handler)(struct l_tls *tls, - const uint8_t *buf, size_t len); - - if (len < 4) - goto decode_error; - - ext_id = l_get_be16(buf + 0); - ext_len = l_get_be16(buf + 2); - buf += 4; - len -= 4; - - if (ext_len > len) - goto decode_error; - - /* - * RFC 5246, Section 7.4.1.4: "There MUST NOT be more than - * one extension of the same type." - */ - if (l_queue_find(seen, tls_ptr_match, L_UINT_TO_PTR(ext_id))) { - TLS_DEBUG("Duplicate extension %u", ext_id); - goto decode_error; - } - - l_queue_push_tail(seen, L_UINT_TO_PTR(ext_id)); - - extension = NULL; - - for (i = 0; tls_extensions[i].name; i++) - if (tls_extensions[i].id == ext_id) { - extension = &tls_extensions[i]; - break; - } - - if (!extension) - goto next; - - handler = client_hello ? - extension->client_handle : extension->server_handle; - - /* - * RFC 5246, Section 7.4.1.4: "If a client receives an - * extension type in ServerHello that it did not request in - * the associated ClientHello, it MUST abort the handshake - * with an unsupported_extension fatal alert." - * There are however servers that include an unsolicited - * Supported Point Format extension where the handshake - * still completes fine if the extension is ignored so we - * do this instead. - */ - if (!client_hello && !handler) { - TLS_DEBUG("non-fatal: %s extension not expected in " - "a ServerHello", extension->name); - goto next; - } - - if (!handler(tls, buf, ext_len)) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "Hello %s extension parse error", - extension->name); - return false; - } - -next: - buf += ext_len; - len -= ext_len; - } - - /* - * Trigger any actions needed when an extension is missing and its - * handler has not been called yet. - */ - for (i = 0; tls_extensions[i].name; i++) { - bool (*handler)(struct l_tls *tls); - - extension = &tls_extensions[i]; - handler = client_hello ? - extension->client_handle_absent : - extension->server_handle_absent; - - if (!handler) - continue; - - if (l_queue_find(seen, tls_ptr_match, - L_UINT_TO_PTR(extension->id))) - continue; - - if (!handler(tls)) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "Hello %s extension missing", - extension->name); - return false; - } - } - - return true; - -decode_error: - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "Hello extensions decode error"); - return false; -} - -static void tls_handle_client_hello(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - uint16_t cipher_suites_size; - uint8_t session_id_size, compression_methods_size; - const uint8_t *cipher_suites; - const uint8_t *compression_methods; - int i; - struct l_queue *extensions_offered = NULL; - enum l_tls_alert_desc alert_desc = TLS_ALERT_HANDSHAKE_FAIL; - - /* Do we have enough for ProtocolVersion + Random + SessionID size? */ - if (len < 2 + 32 + 1) - goto decode_error; - - memcpy(tls->pending.client_random, buf + 2, 32); - session_id_size = buf[34]; - len -= 35; - - /* - * Do we have enough to hold the actual session ID + 2 byte field for - * cipher_suite len + minimum of a single cipher suite identifier - */ - if (len < (size_t) session_id_size + 4) - goto decode_error; - - len -= session_id_size + 2; - - cipher_suites_size = l_get_be16(buf + 35 + session_id_size); - cipher_suites = buf + 37 + session_id_size; - - /* - * Check that size is not odd, more than 0 and we have enough - * data in the packet for cipher_suites_size + 2 bytes for - * compression_methods_size + a single compression method - */ - if (len < (size_t) cipher_suites_size + 2 || - (cipher_suites_size & 1) || cipher_suites_size == 0) - goto decode_error; - - len -= cipher_suites_size + 1; - - compression_methods_size = cipher_suites[cipher_suites_size]; - compression_methods = cipher_suites + cipher_suites_size + 1; - - if (len < (size_t) compression_methods_size || - compression_methods_size == 0) - goto decode_error; - - len -= compression_methods_size; - - extensions_offered = l_queue_new(); - - if (!tls_handle_hello_extensions(tls, compression_methods + - compression_methods_size, - len, extensions_offered)) - goto cleanup; - - /* - * Note: if the client is supplying a SessionID we know it is false - * because our server implementation never generates any SessionIDs - * yet so either the client is attempting something strange or was - * trying to connect somewhere else. We might want to throw an error. - */ - - /* Save client_version for Premaster Secret verification */ - tls->client_version = l_get_be16(buf); - - if (tls->client_version < tls->min_version) { - TLS_DISCONNECT(TLS_ALERT_PROTOCOL_VERSION, 0, - "Client version too low: %02x", - tls->client_version); - goto cleanup; - } - - tls->negotiated_version = tls->client_version > tls->max_version ? - tls->max_version : tls->client_version; - - /* Stop maintaining handshake message hashes other than MD1 and SHA. */ - if (tls->negotiated_version < L_TLS_V12) - for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++) - if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5) - tls_drop_handshake_hash(tls, i); - - TLS_DEBUG("Negotiated TLS " TLS_VER_FMT, - TLS_VER_ARGS(tls->negotiated_version)); - - if (!tls->cipher_suite_pref_list) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "No usable cipher suites"); - goto cleanup; - } - - /* Select a cipher suite according to client's preference list */ - while (cipher_suites_size) { - struct tls_cipher_suite *suite = - tls_find_cipher_suite(cipher_suites); - struct tls_cipher_suite **iter; - const char *error; - - for (iter = tls->cipher_suite_pref_list; *iter; iter++) - if (*iter == suite) - break; - - if (!suite) - TLS_DEBUG("non-fatal: Cipher suite %04x unknown", - l_get_be16(cipher_suites)); - else if (!tls_cipher_suite_is_compatible(tls, suite, &error)) - TLS_DEBUG("non-fatal: %s", error); - else if (!*iter) { - /* - * We have at least one matching compatible suite but - * it is not allowed in this security profile. If the - * handshake ends up failing then we blame the security - * profile. - */ - alert_desc = TLS_ALERT_INSUFFICIENT_SECURITY; - TLS_DEBUG("non-fatal: Cipher suite %s disallowed " - "by config", suite->name); - } else { - tls->pending.cipher_suite = suite; - break; - } - - cipher_suites += 2; - cipher_suites_size -= 2; - } - - if (!cipher_suites_size) { - TLS_DISCONNECT(alert_desc, 0, - "No common cipher suites matching negotiated " - "TLS version and our certificate's key type"); - goto cleanup; - } - - if (!tls_set_prf_hmac(tls)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Error selecting the PRF HMAC"); - goto cleanup; - } - - TLS_DEBUG("Negotiated %s", tls->pending.cipher_suite->name); - - /* Select a compression method */ - - /* CompressionMethod.null must be present in the vector */ - if (!memchr(compression_methods, 0, compression_methods_size)) { - TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, - "No common compression methods"); - goto cleanup; - } - - while (compression_methods_size) { - tls->pending.compression_method = - tls_find_compression_method(*compression_methods); - - if (tls->pending.compression_method) - break; - - compression_methods++; - compression_methods_size--; - } - - TLS_DEBUG("Negotiated %s", tls->pending.compression_method->name); - - if (!tls_send_server_hello(tls, extensions_offered)) - goto cleanup; - - l_queue_destroy(extensions_offered, NULL); - - if (tls->pending.cipher_suite->signature && tls->cert) - if (!tls_send_certificate(tls)) - return; - - if (tls->pending.cipher_suite->key_xchg->send_server_key_exchange) - if (!tls->pending.cipher_suite->key_xchg-> - send_server_key_exchange(tls)) - return; - - /* TODO: don't bother if configured to not authenticate client */ - if (tls->pending.cipher_suite->signature && tls->ca_certs) - if (!tls_send_certificate_request(tls)) - return; - - tls_send_server_hello_done(tls); - - if (tls->pending.cipher_suite->signature && tls->ca_certs) - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CERTIFICATE); - else - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE); - - return; - -decode_error: - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "ClientHello decode error"); - -cleanup: - l_queue_destroy(extensions_offered, NULL); -} - -static void tls_handle_server_hello(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - uint8_t session_id_size, cipher_suite_id[2], compression_method_id; - const char *error; - struct tls_cipher_suite **iter; - int i; - struct l_queue *extensions_seen; - bool result; - - /* Do we have enough for ProtocolVersion + Random + SessionID len ? */ - if (len < 2 + 32 + 1) - goto decode_error; - - memcpy(tls->pending.server_random, buf + 2, 32); - session_id_size = buf[34]; - len -= 35; - - /* Do we have enough for SessionID + CipherSuite ID + Compression ID */ - if (len < (size_t) session_id_size + 2 + 1) - goto decode_error; - - cipher_suite_id[0] = buf[35 + session_id_size + 0]; - cipher_suite_id[1] = buf[35 + session_id_size + 1]; - compression_method_id = buf[35 + session_id_size + 2]; - len -= session_id_size + 2 + 1; - - extensions_seen = l_queue_new(); - result = tls_handle_hello_extensions(tls, buf + 38 + session_id_size, - len, extensions_seen); - l_queue_destroy(extensions_seen, NULL); - - if (!result) - return; - - tls->negotiated_version = l_get_be16(buf); - - if (tls->negotiated_version < tls->min_version || - tls->negotiated_version > tls->max_version) { - TLS_DISCONNECT(tls->negotiated_version < tls->min_version ? - TLS_ALERT_PROTOCOL_VERSION : - TLS_ALERT_ILLEGAL_PARAM, 0, - "Unsupported version %02x", - tls->negotiated_version); - return; - } - - /* Stop maintaining handshake message hashes other than MD1 and SHA. */ - if (tls->negotiated_version < L_TLS_V12) - for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++) - if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5) - tls_drop_handshake_hash(tls, i); - - TLS_DEBUG("Negotiated TLS " TLS_VER_FMT, - TLS_VER_ARGS(tls->negotiated_version)); - - /* Set the new cipher suite and compression method structs */ - tls->pending.cipher_suite = tls_find_cipher_suite(cipher_suite_id); - if (!tls->pending.cipher_suite) { - TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, - "Unknown cipher suite %04x", - l_get_be16(cipher_suite_id)); - return; - } - - for (iter = tls->cipher_suite_pref_list; *iter; iter++) - if (*iter == tls->pending.cipher_suite) - break; - if (!*iter) { - TLS_DISCONNECT(TLS_ALERT_INSUFFICIENT_SECURITY, 0, - "Selected cipher suite %s disallowed by config", - tls->pending.cipher_suite->name); - return; - } - - if (!tls_cipher_suite_is_compatible(tls, tls->pending.cipher_suite, - &error)) { - TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, - "Selected cipher suite not compatible: %s", - error); - return; - } - - if (!tls_set_prf_hmac(tls)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Error selecting the PRF HMAC"); - return; - } - - TLS_DEBUG("Negotiated %s", tls->pending.cipher_suite->name); - - tls->pending.compression_method = - tls_find_compression_method(compression_method_id); - if (!tls->pending.compression_method) { - TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, - "Unknown compression method %i", - compression_method_id); - return; - } - - TLS_DEBUG("Negotiated %s", tls->pending.compression_method->name); - - if (tls->pending.cipher_suite->signature) - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CERTIFICATE); - else - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE); - - return; - -decode_error: - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "ServerHello decode error"); -} - -static void tls_handle_certificate(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - size_t total; - struct l_certchain *certchain = NULL; - struct l_cert *leaf; - size_t der_len; - const uint8_t *der; - bool dummy; - const char *error_str; - - if (len < 3) - goto decode_error; - - /* Length checks */ - total = *buf++ << 16; - total |= *buf++ << 8; - total |= *buf++ << 0; - if (total + 3 != len) - goto decode_error; - - if (tls_parse_certificate_list(buf, total, &certchain) < 0) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "Error decoding peer certificate chain"); - - goto done; - } - - /* - * "Note that a client MAY send no certificates if it does not have any - * appropriate certificate to send in response to the server's - * authentication request." -- for now we unconditionally accept - * an empty certificate chain from the client. Later on we need to - * make this configurable, if we don't want to authenticate the - * client then also don't bother sending a Certificate Request. - */ - if (!certchain) { - if (!tls->server) { - TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, - "Server sent no certificate chain"); - - goto done; - } - - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE); - - goto done; - } - - /* - * Validate the certificate chain's consistency and validate it - * against our CAs if we have any. - */ - if (!l_certchain_verify(certchain, tls->ca_certs, &error_str)) { - TLS_DISCONNECT(TLS_ALERT_BAD_CERT, 0, - "Peer certchain verification failed " - "consistency check%s: %s", tls->ca_certs ? - " or against local CA certs" : "", error_str); - - goto done; - } - - /* - * RFC5246 7.4.2: - * "The end entity certificate's public key (and associated - * restrictions) MUST be compatible with the selected key exchange - * algorithm." - */ - leaf = l_certchain_get_leaf(certchain); - if (!tls->pending.cipher_suite->signature-> - validate_cert_key_type(leaf)) { - TLS_DISCONNECT(TLS_ALERT_UNSUPPORTED_CERT, 0, - "Peer certificate key type incompatible with " - "pending cipher suite %s", - tls->pending.cipher_suite->name); - - goto done; - } - - if (tls->subject_mask && !tls_cert_domains_match_mask(leaf, - tls->subject_mask)) { - char *mask = l_strjoinv(tls->subject_mask, '|'); - - TLS_DISCONNECT(TLS_ALERT_BAD_CERT, 0, - "Peer certificate's subject domain " - "doesn't match %s", mask); - l_free(mask); - - goto done; - } - - /* Save the end-entity certificate and free the chain */ - der = l_cert_get_der_data(leaf, &der_len); - tls->peer_cert = l_cert_new_from_der(der, der_len); - - tls->peer_pubkey = l_cert_get_pubkey(tls->peer_cert); - if (!tls->peer_pubkey) { - TLS_DISCONNECT(TLS_ALERT_UNSUPPORTED_CERT, 0, - "Error loading peer public key to kernel"); - - goto done; - } - - if (!l_key_get_info(tls->peer_pubkey, L_KEY_RSA_PKCS1_V1_5, - L_CHECKSUM_NONE, &tls->peer_pubkey_size, - &dummy)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "Can't l_key_get_info for peer public key"); - - goto done; - } - - tls->peer_pubkey_size /= 8; - - if (tls->server || tls->pending.cipher_suite->key_xchg-> - handle_server_key_exchange) - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE); - else - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO_DONE); - - goto done; - -decode_error: - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "TLS_CERTIFICATE decode error"); - -done: - l_certchain_free(certchain); -} - -static void tls_handle_certificate_request(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - unsigned int cert_type_len, dn_len, i; - - tls->cert_requested = 1; - - cert_type_len = *buf++; - if (len < 1 + cert_type_len + 2) - goto decode_error; - - for (i = 0; i < sizeof(tls_cert_type_pref); i++) - if (memchr(buf, tls_cert_type_pref[i], cert_type_len)) - break; - - if (i == sizeof(tls_cert_type_pref)) { - TLS_DISCONNECT(TLS_ALERT_UNSUPPORTED_CERT, 0, - "Requested certificate types not supported"); - return; - } - - buf += cert_type_len; - len -= 1 + cert_type_len; - - /* - * TODO: parse and save certificate_types, - * supported_signature_algorithms and certificate_authorities - * lists for use in tls_send_certificate. - */ - - if (tls->negotiated_version >= L_TLS_V12) { - enum handshake_hash_type hash; - ssize_t ret = tls_parse_signature_algorithms(tls, buf, len); - - if (ret == -ENOTSUP) { - TLS_DISCONNECT(TLS_ALERT_UNSUPPORTED_CERT, 0, - "No supported signature hash type"); - return; - } - - if (ret < 0) - goto decode_error; - - len -= ret; - buf += ret; - - /* - * We can now safely stop maintaining handshake message - * hashes other than the PRF hash and the one selected for - * signing. - */ - for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) - if (&tls_handshake_hash_data[hash] != tls->prf_hmac && - hash != tls->signature_hash) - tls_drop_handshake_hash(tls, hash); - } - - dn_len = l_get_be16(buf); - if (2 + dn_len != len) - goto decode_error; - - return; - -decode_error: - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "CertificateRequest decode error"); -} - -static void tls_handle_server_hello_done(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - const char *error; - - if (len) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "ServerHello not empty"); - return; - } - - if (tls->cert_requested) - if (!tls_send_certificate(tls)) - return; - - if (!tls->pending.cipher_suite->key_xchg->send_client_key_exchange(tls)) - return; - - if (tls->cert_sent) - if (!tls_send_certificate_verify(tls)) - return; - - tls_send_change_cipher_spec(tls); - - if (!tls_change_cipher_spec(tls, 1, &error)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "change_cipher_spec: %s", error); - return; - } - - tls_send_finished(tls); - - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC); -} - -static bool tls_get_prev_digest_by_type(struct l_tls *tls, - enum handshake_hash_type type, - const uint8_t *data, size_t data_len, - uint8_t *out, size_t *out_len) -{ - size_t len; - - if (!tls->handshake_hash[type]) - return false; - - len = l_checksum_digest_length(tls_handshake_hash_data[type].l_id); - memcpy(out, tls->prev_digest[type], len); - - if (out_len) - *out_len = len; - - return 0; -} - -static void tls_handle_certificate_verify(struct l_tls *tls, - const uint8_t *buf, size_t len) -{ - int i; - - if (!tls->pending.cipher_suite->signature->verify(tls, buf, len, - tls_get_prev_digest_by_type, - NULL, 0)) - return; - - /* Stop maintaining handshake message hashes other than the PRF hash */ - if (tls->negotiated_version >= L_TLS_V12) - for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++) - if (&tls_handshake_hash_data[i] != tls->prf_hmac) - tls_drop_handshake_hash(tls, i); - - /* - * The client's certificate is now verified based on the following - * logic: - * - If we received an (expected) Certificate Verify, we must have - * sent a Certificate Request. - * - If we sent a Certificate Request that's because - * tls->ca_certs is non-NULL. - * - If tls->ca_certs is non-NULL then tls_handle_certificate - * will have checked the whole certificate chain to be valid and - * additionally trusted by our CAs if known. - * - Additionally cipher_suite->signature->verify has just confirmed - * that the peer owns the end-entity certificate because it was - * able to sign the contents of the handshake messages and that - * signature could be verified with the public key from that - * certificate. - */ - tls->peer_authenticated = true; - - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC); -} - -struct dn_element_info { - const char *str; - const struct asn1_oid oid; -}; - -static const struct dn_element_info dn_elements[] = { - { "CN", { 3, { 0x55, 0x04, 0x03 } } }, - { "SN", { 3, { 0x55, 0x04, 0x04 } } }, - { "serialNumber", { 3, { 0x55, 0x04, 0x05 } } }, - { "C", { 3, { 0x55, 0x04, 0x06 } } }, - { "ST", { 3, { 0x55, 0x04, 0x07 } } }, - { "L", { 3, { 0x55, 0x04, 0x08 } } }, - { "street", { 3, { 0x55, 0x04, 0x09 } } }, - { "O", { 3, { 0x55, 0x04, 0x0a } } }, - { "OU", { 3, { 0x55, 0x04, 0x0b } } }, - { "title", { 3, { 0x55, 0x04, 0x0c } } }, - { "telephoneNumber", { 3, { 0x55, 0x04, 0x14 } } }, - { "givenName", { 3, { 0x55, 0x04, 0x2a } } }, - { "initials", { 3, { 0x55, 0x04, 0x2b } } }, - { "emailAddress", { - 9, - { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 } - } }, - { "domainComponent", { - 10, - { 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19 } - } }, - {} -}; - -static void tls_str_escape_append(struct l_string *out, char *str, size_t len) -{ - while (len--) { - switch (*str) { - case '\\': - case '/': - case '=': - l_string_append_c(out, '\\'); - l_string_append_c(out, *str); - break; - default: - l_string_append_c(out, *str); - break; - } - - str++; - } -} - -static char *tls_get_peer_identity_str(struct l_cert *cert) -{ - const uint8_t *dn, *end; - size_t dn_size; - struct l_string *id_str; - - if (!cert) - return NULL; - - dn = l_cert_get_dn(cert, &dn_size); - if (!dn) - return NULL; - - id_str = l_string_new(200); - - end = dn + dn_size; - while (dn < end) { - const uint8_t *set, *seq, *oid, *name; - uint8_t tag; - size_t len, oid_len, name_len; - const struct dn_element_info *info; - - set = asn1_der_find_elem(dn, end - dn, 0, &tag, &len); - if (!set || tag != ASN1_ID_SET) - goto error; - - dn = set + len; - - seq = asn1_der_find_elem(set, len, 0, &tag, &len); - if (!seq || tag != ASN1_ID_SEQUENCE) - goto error; - - oid = asn1_der_find_elem(seq, len, 0, &tag, &oid_len); - if (!oid || tag != ASN1_ID_OID) - goto error; - - name = asn1_der_find_elem(seq, len, 1, &tag, &name_len); - if (!name || (tag != ASN1_ID_PRINTABLESTRING && - tag != ASN1_ID_UTF8STRING && - tag != ASN1_ID_IA5STRING)) - continue; - - for (info = dn_elements; info->str; info++) - if (asn1_oid_eq(&info->oid, oid_len, oid)) - break; - if (!info->str) - continue; - - l_string_append_c(id_str, '/'); - l_string_append(id_str, info->str); - l_string_append_c(id_str, '='); - tls_str_escape_append(id_str, (char *) name, name_len); - } - - return l_string_unwrap(id_str); - -error: - l_string_free(id_str); - return NULL; -} - -static void tls_finished(struct l_tls *tls) -{ - char *peer_identity = NULL; - - if (tls->peer_authenticated) { - peer_identity = tls_get_peer_identity_str(tls->peer_cert); - if (!peer_identity) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "tls_get_peer_identity_str failed"); - return; - } - } - - /* Free up the resources used in the handshake */ - tls_reset_handshake(tls); - - TLS_SET_STATE(TLS_HANDSHAKE_DONE); - tls->ready = true; - - tls->in_callback = true; - tls->ready_handle(peer_identity, tls->user_data); - tls->in_callback = false; - l_free(peer_identity); - - tls_cleanup_handshake(tls); -} - -static void tls_handle_handshake(struct l_tls *tls, int type, - const uint8_t *buf, size_t len) -{ - TLS_DEBUG("Handling a %s of %zi bytes", - tls_handshake_type_to_str(type), len); - - switch (type) { - case TLS_HELLO_REQUEST: - if (tls->server) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in server mode"); - break; - } - - if (len != 0) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "HelloRequest not empty"); - break; - } - - /* - * May be sent by the server at any time but "SHOULD be ignored - * by the client if it arrives in the middle of a handshake" - * and "MAY be ignored by the client if it does not wish to - * renegotiate a session". - */ - - break; - - case TLS_CLIENT_HELLO: - if (!tls->server) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in client mode"); - break; - } - - if (tls->state != TLS_HANDSHAKE_WAIT_HELLO && - tls->state != TLS_HANDSHAKE_DONE) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in state %s", - tls_handshake_state_to_str(tls->state)); - break; - } - - tls_handle_client_hello(tls, buf, len); - - break; - - case TLS_SERVER_HELLO: - if (tls->server) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in server mode"); - break; - } - - if (tls->state != TLS_HANDSHAKE_WAIT_HELLO) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in state %s", - tls_handshake_state_to_str(tls->state)); - break; - } - - tls_handle_server_hello(tls, buf, len); - - break; - - case TLS_CERTIFICATE: - if (tls->state != TLS_HANDSHAKE_WAIT_CERTIFICATE) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in state %s", - tls_handshake_state_to_str(tls->state)); - break; - } - - tls_handle_certificate(tls, buf, len); - - break; - - case TLS_SERVER_KEY_EXCHANGE: - if (tls->server) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in server mode"); - break; - } - - if (tls->state != TLS_HANDSHAKE_WAIT_KEY_EXCHANGE) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in state %s", - tls_handshake_state_to_str(tls->state)); - break; - } - - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO_DONE); - - tls->pending.cipher_suite->key_xchg->handle_server_key_exchange( - tls, buf, len); - - break; - - case TLS_CERTIFICATE_REQUEST: - if (tls->server) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in server mode"); - break; - } - - /* - * Server sends this optionally so in the WAIT_HELLO_DONE - * state we accept either this or a Server Hello Done (below). - */ - if (tls->state != TLS_HANDSHAKE_WAIT_HELLO_DONE || - tls->cert_requested || - !tls->pending.cipher_suite->signature) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in current state " - "or certificate check not supported " - "in pending cipher suite"); - break; - } - - tls_handle_certificate_request(tls, buf, len); - - break; - - case TLS_SERVER_HELLO_DONE: - if (tls->state != TLS_HANDSHAKE_WAIT_HELLO_DONE) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in state %s", - tls_handshake_state_to_str(tls->state)); - break; - } - - tls_handle_server_hello_done(tls, buf, len); - - break; - - case TLS_CERTIFICATE_VERIFY: - if (tls->state != TLS_HANDSHAKE_WAIT_CERTIFICATE_VERIFY) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in state %s", - tls_handshake_state_to_str(tls->state)); - break; - } - - tls_handle_certificate_verify(tls, buf, len); - - break; - - case TLS_CLIENT_KEY_EXCHANGE: - if (!tls->server) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in client mode"); - break; - } - - if (tls->state != TLS_HANDSHAKE_WAIT_KEY_EXCHANGE) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in state %s", - tls_handshake_state_to_str(tls->state)); - break; - } - - /* - * If we accepted a client Certificate message with a - * certificate that has signing capability (TODO: check - * usage bitmask), Certificate Verify is received next. It - * sounds as if this is mandatory for the client although - * this isn't 100% clear. - */ - if (tls->peer_pubkey) - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CERTIFICATE_VERIFY); - else - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC); - - tls->pending.cipher_suite->key_xchg->handle_client_key_exchange( - tls, buf, len); - - break; - - case TLS_FINISHED: - if (tls->state != TLS_HANDSHAKE_WAIT_FINISHED) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Message invalid in state %s", - tls_handshake_state_to_str(tls->state)); - break; - } - - if (!tls_verify_finished(tls, buf, len)) - break; - - if (tls->server) { - const char *error; - - tls_send_change_cipher_spec(tls); - if (!tls_change_cipher_spec(tls, 1, &error)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "change_cipher_spec: %s", - error); - break; - } - tls_send_finished(tls); - } - - /* - * On the client, the server's certificate is now verified - * regardless of the key exchange method, based on the - * following logic: - * - * - tls->ca_certs is non-NULL so tls_handle_certificate - * (always called on the client) must have veritifed the - * server's certificate chain to be valid and additionally - * trusted by our CA. - * - * - the peer owns the end-entity certificate because: - * either: - * - * * (RSA key exchange algorithm case) the correct - * receival of this Finished message confirms the - * posession of the master secret, it is verified by - * both the successful decryption and the MAC of this - * message (either should be enough) because we entered - * the TLS_HANDSHAKE_WAIT_FINISHED state only after - * encryption and MAC were enabled in ChangeCipherSpec. - * To obtain the master secret the server must have been - * able to decrypt the pre_master_secret which we had - * encrypted with the public key from that certificate. - * - * * (ECDHE and DHE key exchange algorithms) server was - * able to sign the client random together with the - * ServerKeyExchange parameters using its certified key - * pair. - */ - if (!tls->server && tls->cipher_suite[0]->signature && - tls->ca_certs) - tls->peer_authenticated = true; - - tls_finished(tls); - - break; - - default: - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Invalid message"); - } -} - -LIB_EXPORT struct l_tls *l_tls_new(bool server, - l_tls_write_cb_t app_data_handler, - l_tls_write_cb_t tx_handler, - l_tls_ready_cb_t ready_handler, - l_tls_disconnect_cb_t disconnect_handler, - void *user_data) -{ - struct l_tls *tls; - - if (!l_key_is_supported(L_KEY_FEATURE_CRYPTO)) - return NULL; - - tls = l_new(struct l_tls, 1); - tls->server = server; - tls->rx = app_data_handler; - tls->tx = tx_handler; - tls->ready_handle = ready_handler; - tls->disconnected = disconnect_handler; - tls->user_data = user_data; - tls->cipher_suite_pref_list = tls_cipher_suite_pref; - tls->min_version = TLS_MIN_VERSION; - tls->max_version = TLS_MAX_VERSION; - - /* If we're the server wait for the Client Hello already */ - if (tls->server) - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO); - else - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_START); - - return tls; -} - -LIB_EXPORT void l_tls_free(struct l_tls *tls) -{ - enum handshake_hash_type hash; - - if (unlikely(!tls)) - return; - - if (tls->in_callback) { - tls->pending_destroy = true; - return; - } - - l_tls_set_cacert(tls, NULL); - l_tls_set_auth_data(tls, NULL, NULL); - l_tls_set_domain_mask(tls, NULL); - - tls_reset_handshake(tls); - tls_cleanup_handshake(tls); - - tls_reset_cipher_spec(tls, 0); - tls_reset_cipher_spec(tls, 1); - - if (tls->record_buf) - l_free(tls->record_buf); - - if (tls->message_buf) - l_free(tls->message_buf); - - for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) - tls_drop_handshake_hash(tls, hash); - - if (tls->debug_destroy) - tls->debug_destroy(tls->debug_data); - - if (tls->cipher_suite_pref_list != tls_cipher_suite_pref) - l_free(tls->cipher_suite_pref_list); - - l_free(tls); -} - -LIB_EXPORT void l_tls_write(struct l_tls *tls, const uint8_t *data, size_t len) -{ - if (unlikely(!tls->ready)) { - return; - } - - tls_tx_record(tls, TLS_CT_APPLICATION_DATA, data, len); -} - -bool tls_handle_message(struct l_tls *tls, const uint8_t *message, - int len, enum tls_content_type type, uint16_t version) -{ - enum handshake_hash_type hash; - const char *error; - - switch (type) { - case TLS_CT_CHANGE_CIPHER_SPEC: - if (len != 1 || message[0] != 0x01) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "ChangeCipherSpec msg decode error"); - - return false; - } - - if (tls->state != TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "ChangeCipherSpec invalid in state %s", - tls_handshake_state_to_str(tls->state)); - - return false; - } - - if (!tls_change_cipher_spec(tls, 0, &error)) { - TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, - "change_cipher_spec: %s", error); - - return false; - } - - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_FINISHED); - - return true; - - case TLS_CT_ALERT: - /* Verify AlertLevel */ - if (message[0] != 0x01 && message[0] != 0x02) { - TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, - "Received bad AlertLevel %i", - message[0]); - - return false; - } - - /* - * On a fatal alert we are obligated to respond with a - * fatal alert and disconnect but also not complain if - * the connection has been torn down by the peer before - * we were able to send our alert. However on a non-fatal - * alert (warning) we're also allowed to panic and send - * a fatal alert, then disconnect, so we do that - * regardless of the alert level. - */ - TLS_DISCONNECT(TLS_ALERT_CLOSE_NOTIFY, message[1], - "Peer sent a %s Alert: %s", - message[0] == 0x02 ? "Fatal" : "Warning", - l_tls_alert_to_str(message[1])); - - return false; - - case TLS_CT_HANDSHAKE: - /* Start hashing the handshake contents on first message */ - if (tls->server && message[0] == TLS_CLIENT_HELLO && - (tls->state == TLS_HANDSHAKE_WAIT_HELLO || - tls->state != TLS_HANDSHAKE_DONE)) - if (!tls_init_handshake_hash(tls)) - return false; - - /* - * Corner case: When handling a Certificate Verify or a - * Finished message we need access to the messages hash from - * before this message was transmitted on the Tx side so we - * can verify it matches the hash the sender included in the - * message. We save it here for that purpose. Everywhere - * else we need to update the hash before handling the new - * message because 1. we may need the new hash to build our - * own Certificate Verify or Finished messages, and 2. we - * update the message hash with newly transmitted messages - * inside tls_tx_handshake which may be called as part of - * handling incoming message, and if we didn't call - * l_checksum_update before, the calls would end up being - * out of order. - */ - if (message[0] == TLS_CERTIFICATE_VERIFY || - message[0] == TLS_FINISHED) - for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) { - if (!tls->handshake_hash[hash]) - continue; - - tls_get_handshake_hash(tls, hash, - tls->prev_digest[hash]); - } - - /* - * RFC 5246, Section 7.4.1.1: - * This message MUST NOT be included in the message hashes - * that are maintained throughout the handshake and used in - * the Finished messages and the certificate verify message. - */ - if (message[0] != TLS_HELLO_REQUEST) - for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) { - if (!tls->handshake_hash[hash]) - continue; - - l_checksum_update(tls->handshake_hash[hash], - message, len); - } - - tls_handle_handshake(tls, message[0], - message + TLS_HANDSHAKE_HEADER_SIZE, - len - TLS_HANDSHAKE_HEADER_SIZE); - - if (tls->pending_destroy) { - l_tls_free(tls); - return false; - } - - return true; - - case TLS_CT_APPLICATION_DATA: - if (!tls->ready) { - TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, - "Application data message before " - "handshake finished"); - - return false; - } - - if (!len) - return true; - - tls->in_callback = true; - tls->rx(message, len, tls->user_data); - tls->in_callback = false; - - if (tls->pending_destroy) { - l_tls_free(tls); - return false; - } - - return true; - } - - return false; -} - -LIB_EXPORT bool l_tls_start(struct l_tls *tls) -{ - if (tls->max_version < tls->min_version) - return false; - - if (!tls->cipher_suite_pref_list) - return false; - - /* This is a nop in server mode */ - if (tls->server) - return true; - - if (tls->state != TLS_HANDSHAKE_WAIT_START) { - TLS_DEBUG("Call invalid in state %s", - tls_handshake_state_to_str(tls->state)); - return false; - } - - if (!tls_init_handshake_hash(tls)) - return false; - - if (!tls_send_client_hello(tls)) - return false; - - TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO); - return true; -} - -LIB_EXPORT void l_tls_close(struct l_tls *tls) -{ - TLS_DISCONNECT(TLS_ALERT_CLOSE_NOTIFY, 0, "Closing session"); -} - -LIB_EXPORT bool l_tls_set_cacert(struct l_tls *tls, struct l_queue *ca_certs) -{ - if (tls->ca_certs) { - l_queue_destroy(tls->ca_certs, - (l_queue_destroy_func_t) l_cert_free); - tls->ca_certs = NULL; - } - - if (ca_certs) { - if (!l_key_is_supported(L_KEY_FEATURE_RESTRICT)) { - TLS_DEBUG("keyctl restrict support missing, " - "check kernel configuration"); - return false; - } - - tls->ca_certs = ca_certs; - } - - return true; -} - -LIB_EXPORT bool l_tls_set_auth_data(struct l_tls *tls, - struct l_certchain *certchain, - struct l_key *priv_key) -{ - if (tls->cert) { - l_certchain_free(tls->cert); - tls->cert = NULL; - } - - if (tls->priv_key) { - l_key_free(tls->priv_key); - tls->priv_key = NULL; - tls->priv_key_size = 0; - } - - if (certchain) - tls->cert = certchain; - - if (priv_key) { - bool is_public = true; - - tls->priv_key = priv_key; - - if (!l_key_get_info(tls->priv_key, L_KEY_RSA_PKCS1_V1_5, - L_CHECKSUM_NONE, &tls->priv_key_size, - &is_public) || is_public) { - TLS_DEBUG("Not a private key or l_key_get_info failed"); - tls->cert = NULL; - tls->priv_key = NULL; - tls->priv_key_size = 0; - return false; - } - - tls->priv_key_size /= 8; - } - - return true; -} - -bool tls_set_cipher_suites(struct l_tls *tls, const char **suite_list) -{ - struct tls_cipher_suite **suite; - - if (tls->cipher_suite_pref_list != tls_cipher_suite_pref) - l_free(tls->cipher_suite_pref_list); - - if (!suite_list) { - /* Use our default cipher suite preference list */ - tls->cipher_suite_pref_list = tls_cipher_suite_pref; - return true; - } - - tls->cipher_suite_pref_list = l_new(struct tls_cipher_suite *, - l_strv_length((char **) suite_list) + 1); - suite = tls->cipher_suite_pref_list; - - for (; *suite_list; suite_list++) { - unsigned int i; - - for (i = 0; tls_cipher_suite_pref[i]; i++) - if (!strcmp(tls_cipher_suite_pref[i]->name, - *suite_list)) - break; - - if (tls_cipher_suite_pref[i]) - *suite++ = tls_cipher_suite_pref[i]; - else - TLS_DEBUG("Cipher suite %s is not supported", - *suite_list); - } - - if (suite > tls->cipher_suite_pref_list) - return true; - - TLS_DEBUG("None of the supplied suite names is supported"); - l_free(suite); - tls->cipher_suite_pref_list = NULL; - return false; -} - -LIB_EXPORT void l_tls_set_version_range(struct l_tls *tls, - enum l_tls_version min_version, - enum l_tls_version max_version) -{ - tls->min_version = - (min_version && min_version > TLS_MIN_VERSION) ? - min_version : TLS_MIN_VERSION; - tls->max_version = - (max_version && max_version < TLS_MAX_VERSION) ? - max_version : TLS_MAX_VERSION; -} - -/** - * l_tls_set_domain_mask: - * @tls: TLS object being configured - * @mask: NULL-terminated array of domain masks - * - * Sets a mask for domain names contained in the peer certificate - * (eg. the subject Common Name) to be matched against. If none of the - * domains match the any mask, authentication will fail. At least one - * domain has to match at least one mask from the list. - * - * The masks are each split into segments at the dot characters and each - * segment must match the corresponding label of the domain name -- - * a domain name is a sequence of labels joined by dots. An asterisk - * segment in the mask matches any label. An asterisk segment at the - * beginning of the mask matches one or more consecutive labels from - * the beginning of the domain string. - */ -LIB_EXPORT void l_tls_set_domain_mask(struct l_tls *tls, char **mask) -{ - l_strv_free(tls->subject_mask); - - tls->subject_mask = l_strv_copy(mask); -} - -LIB_EXPORT const char *l_tls_alert_to_str(enum l_tls_alert_desc desc) -{ - switch (desc) { - case TLS_ALERT_CLOSE_NOTIFY: - return "close_notify"; - case TLS_ALERT_UNEXPECTED_MESSAGE: - return "unexpected_message"; - case TLS_ALERT_BAD_RECORD_MAC: - return "bad_record_mac"; - case TLS_ALERT_DECRYPT_FAIL_RESERVED: - return "decryption_failure_RESERVED"; - case TLS_ALERT_RECORD_OVERFLOW: - return "record_overflow"; - case TLS_ALERT_DECOMPRESS_FAIL: - return "decompression_failure"; - case TLS_ALERT_HANDSHAKE_FAIL: - return "handshake_failure"; - case TLS_ALERT_NO_CERT_RESERVED: - return "no_certificate_RESERVED"; - case TLS_ALERT_BAD_CERT: - return "bad_certificate"; - case TLS_ALERT_UNSUPPORTED_CERT: - return "unsupported_certificate"; - case TLS_ALERT_CERT_REVOKED: - return "certificate_revoked"; - case TLS_ALERT_CERT_EXPIRED: - return "certificate_expired"; - case TLS_ALERT_CERT_UNKNOWN: - return "certificate_unknown"; - case TLS_ALERT_ILLEGAL_PARAM: - return "illegal_parameter"; - case TLS_ALERT_UNKNOWN_CA: - return "unknown_ca"; - case TLS_ALERT_ACCESS_DENIED: - return "access_denied"; - case TLS_ALERT_DECODE_ERROR: - return "decode_error"; - case TLS_ALERT_DECRYPT_ERROR: - return "decrypt_error"; - case TLS_ALERT_EXPORT_RES_RESERVED: - return "export_restriction_RESERVED"; - case TLS_ALERT_PROTOCOL_VERSION: - return "protocol_version"; - case TLS_ALERT_INSUFFICIENT_SECURITY: - return "insufficient_security"; - case TLS_ALERT_INTERNAL_ERROR: - return "internal_error"; - case TLS_ALERT_USER_CANCELED: - return "user_canceled"; - case TLS_ALERT_NO_RENEGOTIATION: - return "no_renegotiation"; - case TLS_ALERT_UNSUPPORTED_EXTENSION: - return "unsupported_extension"; - } - - return NULL; -} - -const char *tls_handshake_state_to_str(enum tls_handshake_state state) -{ - static char buf[100]; - - switch (state) { - SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_START) - SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_HELLO) - SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_CERTIFICATE) - SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE) - SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_HELLO_DONE) - SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_CERTIFICATE_VERIFY) - SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC) - SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_FINISHED) - SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_DONE) - } - - snprintf(buf, sizeof(buf), "tls_handshake_state(%i)", state); - return buf; -} - -int tls_parse_certificate_list(const void *data, size_t len, - struct l_certchain **out_certchain) -{ - const uint8_t *buf = data; - struct l_certchain *chain = NULL; - - while (len) { - struct l_cert *cert; - size_t cert_len; - - if (len < 3) - goto decode_error; - - cert_len = *buf++ << 16; - cert_len |= *buf++ << 8; - cert_len |= *buf++ << 0; - - if (cert_len + 3 > len) - goto decode_error; - - cert = l_cert_new_from_der(buf, cert_len); - if (!cert) - goto decode_error; - - if (!chain) { - chain = certchain_new_from_leaf(cert); - if (!chain) - goto decode_error; - } else - certchain_link_issuer(chain, cert); - - buf += cert_len; - len -= cert_len + 3; - } - - if (out_certchain) - *out_certchain = chain; - else - l_certchain_free(chain); - - return 0; - -decode_error: - l_certchain_free(chain); - return -EBADMSG; -} - -LIB_EXPORT bool l_tls_set_debug(struct l_tls *tls, l_tls_debug_cb_t function, - void *user_data, l_tls_destroy_cb_t destroy) -{ - if (unlikely(!tls)) - return false; - - if (tls->debug_destroy) - tls->debug_destroy(tls->debug_data); - - tls->debug_handler = function; - tls->debug_destroy = destroy; - tls->debug_data = user_data; - - return true; -} diff --git a/ell/tls.h b/ell/tls.h deleted file mode 100644 index b67492b..0000000 --- a/ell/tls.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Embedded Linux library - * - * Copyright (C) 2015 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __ELL_TLS_H -#define __ELL_TLS_H - -#ifdef __cplusplus -extern "C" { -#endif - -enum l_tls_version { - L_TLS_V10 = ((3 << 8) | 1), - L_TLS_V11 = ((3 << 8) | 2), - L_TLS_V12 = ((3 << 8) | 3), - L_TLS_V13 = ((3 << 8) | 4), /* Not supported */ -}; - -struct l_tls; -struct l_key; -struct l_certchain; -struct l_queue; - -enum l_tls_alert_desc { - TLS_ALERT_CLOSE_NOTIFY = 0, - TLS_ALERT_UNEXPECTED_MESSAGE = 10, - TLS_ALERT_BAD_RECORD_MAC = 20, - TLS_ALERT_DECRYPT_FAIL_RESERVED = 21, - TLS_ALERT_RECORD_OVERFLOW = 22, - TLS_ALERT_DECOMPRESS_FAIL = 30, - TLS_ALERT_HANDSHAKE_FAIL = 40, - TLS_ALERT_NO_CERT_RESERVED = 41, - TLS_ALERT_BAD_CERT = 42, - TLS_ALERT_UNSUPPORTED_CERT = 43, - TLS_ALERT_CERT_REVOKED = 44, - TLS_ALERT_CERT_EXPIRED = 45, - TLS_ALERT_CERT_UNKNOWN = 46, - TLS_ALERT_ILLEGAL_PARAM = 47, - TLS_ALERT_UNKNOWN_CA = 48, - TLS_ALERT_ACCESS_DENIED = 49, - TLS_ALERT_DECODE_ERROR = 50, - TLS_ALERT_DECRYPT_ERROR = 51, - TLS_ALERT_EXPORT_RES_RESERVED = 60, - TLS_ALERT_PROTOCOL_VERSION = 70, - TLS_ALERT_INSUFFICIENT_SECURITY = 71, - TLS_ALERT_INTERNAL_ERROR = 80, - TLS_ALERT_USER_CANCELED = 90, - TLS_ALERT_NO_RENEGOTIATION = 100, - TLS_ALERT_UNSUPPORTED_EXTENSION = 110, -}; - -typedef void (*l_tls_write_cb_t)(const uint8_t *data, size_t len, - void *user_data); -typedef void (*l_tls_ready_cb_t)(const char *peer_identity, void *user_data); -typedef void (*l_tls_disconnect_cb_t)(enum l_tls_alert_desc reason, - bool remote, void *user_data); -typedef void (*l_tls_debug_cb_t)(const char *str, void *user_data); -typedef void (*l_tls_destroy_cb_t)(void *user_data); - -/* - * app_data_handler gets called with newly received decrypted data. - * tx_handler gets called to send TLS payloads off to remote end. - * ready_handler gets called when l_tls_write calls are first accepted. - */ -struct l_tls *l_tls_new(bool server, l_tls_write_cb_t app_data_handler, - l_tls_write_cb_t tx_handler, - l_tls_ready_cb_t ready_handler, - l_tls_disconnect_cb_t disconnect_handler, - void *user_data); - -void l_tls_free(struct l_tls *tls); - -/* Begin sending connection setup messages to the server */ -bool l_tls_start(struct l_tls *tls); - -/* Properly disconnect a connected session */ -void l_tls_close(struct l_tls *tls); - -/* Submit plaintext data to be encrypted and transmitted */ -void l_tls_write(struct l_tls *tls, const uint8_t *data, size_t len); - -/* Submit TLS payload from underlying transport to be decrypted */ -void l_tls_handle_rx(struct l_tls *tls, const uint8_t *data, size_t len); - -/* - * If peer is to be authenticated, supply the CA certificates. On success - * the l_tls object takes ownership of the queue and the individual l_cert - * objects and they should not be freed by the caller afterwards. - */ -bool l_tls_set_cacert(struct l_tls *tls, struct l_queue *ca_certs); - -/* - * If we are to be authenticated, supply our certificate and private key. - * On the client this is optional. On success, the l_tls object takes - * ownership of the certchain and the key objects and they should not be - * freed by the caller afterwards. - * TODO: it may also be useful for the caller to be able to supply one - * certificate of each type so they can be used depending on which is compatible - * with the negotiated parameters. - */ -bool l_tls_set_auth_data(struct l_tls *tls, - struct l_certchain *certchain, - struct l_key *priv_key); - -void l_tls_set_version_range(struct l_tls *tls, - enum l_tls_version min_version, - enum l_tls_version max_version); - -void l_tls_set_domain_mask(struct l_tls *tls, char **mask); - -const char *l_tls_alert_to_str(enum l_tls_alert_desc desc); - -enum l_checksum_type; - -bool l_tls_prf_get_bytes(struct l_tls *tls, bool use_master_secret, - const char *label, uint8_t *buf, size_t len); - -bool l_tls_set_debug(struct l_tls *tls, l_tls_debug_cb_t function, - void *user_data, l_tls_destroy_cb_t destroy); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_TLS_H */ diff --git a/ell/uintset.c b/ell/uintset.c deleted file mode 100644 index b88e28e..0000000 --- a/ell/uintset.c +++ /dev/null @@ -1,532 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2015-2019 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include - -#include "uintset.h" -#include "private.h" - -#define BITS_PER_LONG (sizeof(unsigned long) * 8) - -static inline int __ffz(unsigned long word) -{ - return __builtin_ctzl(~word); -} - -static inline int __fls(unsigned long word) -{ - return word ? sizeof(word) * 8 - __builtin_clzl(word) : 0; -} - -static inline int __ffs(unsigned long word) -{ - return __builtin_ctzl(word); -} - -static unsigned long find_first_zero_bit(const unsigned long *addr, - unsigned long size, - unsigned long start) -{ - unsigned long i; - unsigned long mask = ~0UL << (start & (BITS_PER_LONG - 1)); - unsigned long p; - - for (i = start / BITS_PER_LONG; i * BITS_PER_LONG < size; i++) { - p = addr[i]; - - if (mask) { - p |= ~mask; - mask = 0; - } - - if (p == ~0UL) - continue; - - return i * BITS_PER_LONG + __ffz(p); - } - - return size; -} - -static unsigned long find_first_bit(const unsigned long *addr, - unsigned long size) -{ - unsigned long result = 0; - unsigned long tmp; - - while (size >= BITS_PER_LONG) { - tmp = *addr; - addr += 1; - - if (tmp) - goto found; - - result += BITS_PER_LONG; - size -= BITS_PER_LONG; - } - - if (!size) - return result; - - tmp = *addr; - if (!tmp) - return result + size; - -found: - return result + __ffs(tmp); -} - -static unsigned long find_last_bit(const unsigned long *addr, unsigned int size) -{ - unsigned long words; - unsigned long tmp; - long i; - - /* Bits out of bounds are always zero, start at last word */ - words = (size + BITS_PER_LONG - 1) / BITS_PER_LONG; - - for (i = words - 1; i >= 0; i -= 1) { - tmp = addr[i]; - - if (!tmp) - continue; - - return i * BITS_PER_LONG + __fls(tmp) - 1; - } - - /* Not found */ - return size; -} - -static unsigned long find_next_bit(const unsigned long *addr, - unsigned long size, - unsigned long bit) -{ - unsigned long mask; - unsigned long offset; - - if (bit >= size) - return size; - - addr += bit / BITS_PER_LONG; - offset = bit % BITS_PER_LONG; - bit -= offset; - - if (offset) { - mask = *addr & ~(~0UL >> (BITS_PER_LONG - offset)); - if (mask) - return bit + __ffs(mask); - - bit += BITS_PER_LONG; - addr++; - } - - for (size -= bit; size >= BITS_PER_LONG; - size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) { - if (!*addr) - continue; - - return bit + __ffs(*addr); - } - - if (!size) - return bit; - - mask = *addr & (~0UL >> (BITS_PER_LONG - size)); - if (mask) - bit += __ffs(mask); - else - bit += size; - - return bit; -} - -struct l_uintset { - unsigned long *bits; - uint16_t size; - uint32_t min; - uint32_t max; -}; - -/** - * l_uintset_new_from_range: - * @min: The minimum value of the set of numbers contained in the set - * @max: The maximum value of the set of numbers contained - * - * Creates a new empty collection of unsigned integers. The size of the set - * is limited to roughly 2^16 entries. @min and @max give the minimum and - * maximum elements of the set. - * - * Returns: A newly allocated l_uintset object, and NULL otherwise. - **/ -LIB_EXPORT struct l_uintset *l_uintset_new_from_range(uint32_t min, - uint32_t max) -{ - struct l_uintset *ret; - unsigned int size = max - min + 1; - - if (size > USHRT_MAX) - return NULL; - - ret = l_new(struct l_uintset, 1); - ret->bits = l_new(unsigned long, - (size + BITS_PER_LONG - 1) / BITS_PER_LONG); - ret->size = size; - ret->min = min; - ret->max = max; - - return ret; -} - -/** - * l_uintset_new: - * @size: The maximum size of the set - * - * Creates a new empty collection of unsigned integers. The size of the set - * is limited to roughly 2^16 entries. The set is created with minimum value - * of 1 and maximum value equal to size. - * - * Returns: A newly allocated l_uintset object, and NULL otherwise. - **/ -LIB_EXPORT struct l_uintset *l_uintset_new(unsigned int size) -{ - return l_uintset_new_from_range(1, size); -} - -/** - * l_uintset_free: - * @set: The set to destroy - * - * De-allocated the set object. - **/ -LIB_EXPORT void l_uintset_free(struct l_uintset *set) -{ - if (unlikely(!set)) - return; - - l_free(set->bits); - l_free(set); -} - -/** - * l_uintset_take: - * @set: The set of numbers - * @number: The number to remove from the set - * - * Removes the @number from the @set. No checking is performed whether the - * number is actually contained in the set. However, basic bounds checking - * is performed to make sure the number taken can actually exist in the set. - * - * Returns: true if the number was removed, and false otherwise. - **/ -LIB_EXPORT bool l_uintset_take(struct l_uintset *set, uint32_t number) -{ - uint32_t offset; - - if (unlikely(!set)) - return false; - - offset = (number - set->min) / BITS_PER_LONG; - - number -= set->min; - - if (number > set->size) - return false; - - number %= BITS_PER_LONG; - - set->bits[offset] &= ~(1UL << number); - - return true; -} - -/** - * l_uintset_put: - * @set: The set of numbers - * @number: The number to add to the set - * - * Adds the @number to the @set. No checking is performed whether the - * number is already contained in the set. However, basic bounds checking - * is performed to make sure the number being added can actually exist in - * the set. - * - * Returns: true if the number was added, and false otherwise. - **/ -LIB_EXPORT bool l_uintset_put(struct l_uintset *set, uint32_t number) -{ - uint32_t bit; - uint32_t offset; - - if (unlikely(!set)) - return false; - - bit = number - set->min; - if (bit >= set->size) - return false; - - offset = bit / BITS_PER_LONG; - set->bits[offset] |= 1UL << (bit % BITS_PER_LONG); - - return true; -} - -/** - * l_uintset_contains: - * @set: The set of numbers - * @number: The number to search for - * - * Returns: true if the number is in the set, and false otherwise. - **/ -LIB_EXPORT bool l_uintset_contains(struct l_uintset *set, uint32_t number) -{ - uint32_t bit; - uint32_t offset; - - if (unlikely(!set)) - return false; - - bit = number - set->min; - if (bit >= set->size) - return false; - - offset = bit / BITS_PER_LONG; - if (set->bits[offset] & (1UL << (bit % BITS_PER_LONG))) - return true; - - return false; -} - -/** - * l_uintset_get_min: - * @set: The set of numbers - * - * Returns: the minimum possible value of the set. If @set is NULL returns - * UINT_MAX. - **/ -LIB_EXPORT uint32_t l_uintset_get_min(struct l_uintset *set) -{ - if (unlikely(!set)) - return UINT_MAX; - - return set->min; -} - -/** - * l_uintset_get_max: - * @set: The set of numbers - * - * Returns: the maximum possible value of the set. If @set is NULL returns - * UINT_MAX. - **/ -LIB_EXPORT uint32_t l_uintset_get_max(struct l_uintset *set) -{ - if (unlikely(!set)) - return UINT_MAX; - - return set->max; -} - -/** - * l_uintset_find_unused_min: - * @set: The set of numbers - * - * Returns: The minimum number that is not preset in the set. If the set of - * numbers is fully populated, returns l_uintset_get_max(set) + 1. If @set is - * NULL returns UINT_MAX. - **/ -LIB_EXPORT uint32_t l_uintset_find_unused_min(struct l_uintset *set) -{ - unsigned int bit; - - if (unlikely(!set)) - return UINT_MAX; - - bit = find_first_zero_bit(set->bits, set->size, 0); - - if (bit >= set->size) - return set->max + 1; - - return bit + set->min; -} - -/** - * l_uintset_find_unused: - * @set: The set of numbers - * @start: The starting point - * - * Returns: First number not in the set starting at position @start (inclusive). - * If all numbers in the set starting at @start until l_uintset_get_max(set) - * are taken, the starting position is set to the minimum and the search starts - * again. If the set of numbers is fully populated, this function returns - * l_uintset_get_max(set) + 1. If @set is NULL returns UINT_MAX. - **/ -LIB_EXPORT uint32_t l_uintset_find_unused(struct l_uintset *set, uint32_t start) -{ - unsigned int bit; - - if (unlikely(!set)) - return UINT_MAX; - - if (start < set->min || start > set->max) - return set->max + 1; - - bit = find_first_zero_bit(set->bits, set->size, start - set->min); - if (bit >= set->size) - bit = find_first_zero_bit(set->bits, set->size, 0); - - if (bit >= set->size) - return set->max + 1; - - return bit + set->min; -} - -/** - * l_uintset_find_max: - * @set: The set of numbers - * - * Returns: The maximum number preset in the set. If the set of numbers is - * empty returns l_uintset_get_max(set) + 1. If @set is NULL returns UINT_MAX. - **/ -LIB_EXPORT uint32_t l_uintset_find_max(struct l_uintset *set) -{ - unsigned int bit; - - if (unlikely(!set)) - return UINT_MAX; - - bit = find_last_bit(set->bits, set->size); - - if (bit >= set->size) - return set->max + 1; - - return bit + set->min; -} - -/** - * l_uintset_find_min: - * @set: The set of numbers - * - * Returns: The minimum number preset in the set. If the set of numbers is - * empty returns l_uintset_get_max(set) + 1. If @set is NULL returns UINT_MAX. - **/ -LIB_EXPORT uint32_t l_uintset_find_min(struct l_uintset *set) -{ - unsigned int bit; - - if (unlikely(!set)) - return UINT_MAX; - - bit = find_first_bit(set->bits, set->size); - - if (bit >= set->size) - return set->max + 1; - - return bit + set->min; -} - -/** - * l_uintset_foreach: - * @set: The set of numbers - * @function: callback function - * @user_data: user data given to callback function - * - * Call @function for every given number in @set. - **/ -LIB_EXPORT void l_uintset_foreach(struct l_uintset *set, - l_uintset_foreach_func_t function, - void *user_data) -{ - unsigned int bit; - - if (unlikely(!set || !function)) - return; - - for (bit = find_first_bit(set->bits, set->size); bit < set->size; - bit = find_next_bit(set->bits, set->size, bit + 1)) - function(set->min + bit, user_data); -} - -/** - * l_uintset_intersect: - * @set_a: The set of numbers - * @set_b: The set of numbers - * - * Intersects the two sets of numbers of an equal base, e.g.: - * l_uintset_get_min(set_a) must be equal to l_uintset_get_min(set_b) and - * l_uintset_get_max(set_a) must be equal to l_uintset_get_max(set_b) - * - * Returns: A newly allocated l_uintset object containing the intersection of - * @set_a and @set_b. If the bases are not equal returns NULL. If either @set_a - * or @set_b is NULL returns NULL. - **/ -LIB_EXPORT struct l_uintset *l_uintset_intersect(const struct l_uintset *set_a, - const struct l_uintset *set_b) -{ - struct l_uintset *intersection; - uint32_t offset; - uint32_t offset_max; - - if (unlikely(!set_a || !set_b)) - return NULL; - - if (unlikely(set_a->min != set_b->min || set_a->max != set_b->max)) - return NULL; - - intersection = l_uintset_new_from_range(set_a->min, set_a->max); - - offset_max = (set_a->size + BITS_PER_LONG - 1) / BITS_PER_LONG; - - for (offset = 0; offset < offset_max; offset++) - intersection->bits[offset] = - set_a->bits[offset] & set_b->bits[offset]; - - return intersection; -} - -/** - * l_uintset_isempty - * @set: The set of numbers - * - * Returns true if the uintset has no entries, or if set is NULL. - */ -LIB_EXPORT bool l_uintset_isempty(const struct l_uintset *set) -{ - uint16_t i; - uint32_t offset_max; - - if (unlikely(!set)) - return true; - - offset_max = (set->size + BITS_PER_LONG - 1) / BITS_PER_LONG; - - for (i = 0; i < offset_max; i++) { - if (set->bits[i]) - return false; - } - - return true; -} diff --git a/ell/uintset.h b/ell/uintset.h deleted file mode 100644 index 8215def..0000000 --- a/ell/uintset.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2015-2019 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_UINTSET_H -#define __ELL_UINTSET_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -typedef void (*l_uintset_foreach_func_t) (uint32_t number, void *user_data); - -struct l_uintset; - -struct l_uintset *l_uintset_new_from_range(uint32_t min, uint32_t max); -struct l_uintset *l_uintset_new(unsigned int size); -void l_uintset_free(struct l_uintset *set); - -bool l_uintset_contains(struct l_uintset *set, uint32_t number); -bool l_uintset_take(struct l_uintset *set, uint32_t number); -bool l_uintset_put(struct l_uintset *set, uint32_t number); - -uint32_t l_uintset_get_min(struct l_uintset *set); -uint32_t l_uintset_get_max(struct l_uintset *set); - -uint32_t l_uintset_find_max(struct l_uintset *set); -uint32_t l_uintset_find_min(struct l_uintset *set); - -uint32_t l_uintset_find_unused_min(struct l_uintset *set); -uint32_t l_uintset_find_unused(struct l_uintset *set, uint32_t start); - -void l_uintset_foreach(struct l_uintset *set, - l_uintset_foreach_func_t function, void *user_data); - -struct l_uintset *l_uintset_intersect(const struct l_uintset *set_a, - const struct l_uintset *set_b); -bool l_uintset_isempty(const struct l_uintset *set); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_UINTSET_H */ diff --git a/ell/utf8.c b/ell/utf8.c deleted file mode 100644 index 44601dc..0000000 --- a/ell/utf8.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "util.h" -#include "strv.h" -#include "utf8.h" -#include "private.h" - -/** - * SECTION:utf8 - * @short_description: UTF-8 utility function - * - * UTF-8 string handling support - */ - -LIB_EXPORT unsigned char l_ascii_table[256] = { - [0x00 ... 0x08] = L_ASCII_CNTRL, - [0x09 ... 0x0D] = L_ASCII_CNTRL | L_ASCII_SPACE, - [0x0E ... 0x1F] = L_ASCII_CNTRL, - [0x20] = L_ASCII_PRINT | L_ASCII_SPACE, - [0x21 ... 0x2F] = L_ASCII_PRINT | L_ASCII_PUNCT, - [0x30 ... 0x39] = L_ASCII_DIGIT | L_ASCII_XDIGIT | L_ASCII_PRINT, - [0x3A ... 0x40] = L_ASCII_PRINT | L_ASCII_PUNCT, - [0x41 ... 0x46] = L_ASCII_PRINT | L_ASCII_XDIGIT | L_ASCII_UPPER, - [0x47 ... 0x5A] = L_ASCII_PRINT | L_ASCII_UPPER, - [0x5B ... 0x60] = L_ASCII_PRINT | L_ASCII_PUNCT, - [0x61 ... 0x66] = L_ASCII_PRINT | L_ASCII_XDIGIT | L_ASCII_LOWER, - [0x67 ... 0x7A] = L_ASCII_PRINT | L_ASCII_LOWER, - [0x7B ... 0x7E] = L_ASCII_PRINT | L_ASCII_PUNCT, - [0x7F] = L_ASCII_CNTRL, - [0x80 ... 0xFF] = 0, -}; - -static inline bool __attribute__ ((always_inline)) - valid_unicode(wchar_t c) -{ - if (c <= 0xd7ff) - return true; - - if (c < 0xe000 || c > 0x10ffff) - return false; - - if (c >= 0xfdd0 && c <= 0xfdef) - return false; - - if ((c & 0xfffe) == 0xfffe) - return false; - - return true; -} - -/** - * l_utf8_get_codepoint - * @str: a pointer to codepoint data - * @len: maximum bytes to read - * @cp: destination for codepoint - * - * Returns: number of bytes read, or -1 for invalid coddepoint - **/ -LIB_EXPORT int l_utf8_get_codepoint(const char *str, size_t len, wchar_t *cp) -{ - static const wchar_t mins[3] = { 1 << 7, 1 << 11, 1 << 16 }; - unsigned int expect_bytes; - wchar_t val; - size_t i; - - if (len == 0) - return 0; - - if ((signed char) str[0] > 0) { - *cp = str[0]; - return 1; - } - - expect_bytes = __builtin_clz(~((unsigned char)str[0] << 24)); - - if (expect_bytes < 2 || expect_bytes > 4) - goto error; - - if (expect_bytes > len) - goto error; - - val = str[0] & (0xff >> (expect_bytes + 1)); - - for (i = 1; i < expect_bytes; i++) { - if ((str[i] & 0xc0) != 0x80) - goto error; - - val <<= 6; - val |= str[i] & 0x3f; - } - - if (val < mins[expect_bytes - 2]) - goto error; - - if (valid_unicode(val) == false) - goto error; - - *cp = val; - return expect_bytes; - -error: - return -1; -} - -/** - * l_utf8_validate: - * @str: a pointer to character data - * @len: max bytes to validate - * @end: return location for end of valid data - * - * Validates UTF-8 encoded text. If @end is non-NULL, then the end of - * the valid range will be stored there (i.e. the start of the first - * invalid character if some bytes were invalid, or the end of the text - * being validated otherwise). - * - * Returns: Whether the text was valid UTF-8 - **/ -LIB_EXPORT bool l_utf8_validate(const char *str, size_t len, const char **end) -{ - size_t pos = 0; - int ret; - wchar_t val; - - while (pos < len && str[pos]) { - ret = l_utf8_get_codepoint(str + pos, len - pos, &val); - - if (ret < 0) - goto error; - - pos += ret; - } - -error: - if (end) - *end = str + pos; - - if (pos != len) - return false; - - return true; -} - -/** - * l_utf8_strlen: - * @str: a pointer to character data - * - * Computes the number of UTF-8 characters (not bytes) in the string given - * by @str. - * - * Returns: The number of UTF-8 characters in the string - **/ -LIB_EXPORT size_t l_utf8_strlen(const char *str) -{ - size_t l = 0; - size_t i; - unsigned char b; - - for (i = 0; str[i]; i++) { - b = str[i]; - - if ((b >> 6) == 2) - l += 1; - } - - return i - l; -} - -static inline int __attribute__ ((always_inline)) - utf8_length(wchar_t c) -{ - if (c <= 0x7f) - return 1; - - if (c <= 0x7ff) - return 2; - - if (c <= 0xffff) - return 3; - - return 4; -} - -static inline uint16_t __attribute__ ((always_inline)) - surrogate_value(uint16_t h, uint16_t l) -{ - return 0x10000 + (h - 0xd800) * 0x400 + l - 0xdc00; -} - -/* - * l_utf8_from_wchar: - * @c: a wide-character to convert - * @out_buf: Buffer to write out to - * - * Assumes c is valid unicode and out_buf contains enough space for a single - * utf8 character (maximum 4 bytes) - * Returns: number of characters written - */ -LIB_EXPORT size_t l_utf8_from_wchar(wchar_t c, char *out_buf) -{ - int len = utf8_length(c); - int i; - - if (len == 1) { - out_buf[0] = c; - return 1; - } - - for (i = len - 1; i; i--) { - out_buf[i] = (c & 0x3f) | 0x80; - c >>= 6; - } - - out_buf[0] = (0xff << (8 - len)) | c; - return len; -} - -/** - * l_utf8_from_utf16: - * @utf16: Array of UTF16 characters - * @utf16_size: The size of the @utf16 array in bytes. Must be a multiple of 2. - * - * Returns: A newly-allocated buffer containing UTF16 encoded string converted - * to UTF8. The UTF8 string will always be null terminated, even if the - * original UTF16 string was not. - **/ -LIB_EXPORT char *l_utf8_from_utf16(const void *utf16, ssize_t utf16_size) -{ - char *utf8; - size_t utf8_len = 0; - wchar_t high_surrogate = 0; - ssize_t i = 0; - uint16_t in; - wchar_t c; - - if (unlikely(utf16_size % 2)) - return NULL; - - while (utf16_size < 0 || i < utf16_size) { - in = l_get_u16(utf16 + i); - - if (!in) - break; - - if (in >= 0xdc00 && in < 0xe000) { - if (high_surrogate) - c = surrogate_value(high_surrogate, in); - else - return NULL; - - high_surrogate = 0; - } else { - if (high_surrogate) - return NULL; - - if (in >= 0xd800 && in < 0xdc00) { - high_surrogate = in; - goto next; - } - - c = in; - } - - if (!valid_unicode(c)) - return NULL; - - utf8_len += utf8_length(c); -next: - i += 2; - } - - if (high_surrogate) - return NULL; - - utf8 = l_malloc(utf8_len + 1); - utf8_len = 0; - i = 0; - - while (utf16_size < 0 || i < utf16_size) { - in = l_get_u16(utf16 + i); - - if (!in) - break; - - if (in >= 0xd800 && in < 0xdc00) { - high_surrogate = in; - i += 2; - in = l_get_u16(utf16 + i); - c = surrogate_value(high_surrogate, in); - } else - c = in; - - utf8_len += l_utf8_from_wchar(c, utf8 + utf8_len); - i += 2; - } - - utf8[utf8_len] = '\0'; - - return utf8; -} - -/** - * l_utf8_to_utf16: - * @utf8: UTF8 formatted string - * @out_size: The size in bytes of the converted utf16 string - * - * Converts a UTF8 formatted string to UTF16. It is assumed that the string - * is valid UTF8 and no sanity checking is performed. - * - * Returns: A newly-allocated buffer containing UTF8 encoded string converted - * to UTF16. The UTF16 string will always be null terminated. - **/ -LIB_EXPORT void *l_utf8_to_utf16(const char *utf8, size_t *out_size) -{ - const char *c; - wchar_t wc; - int len; - uint16_t *utf16; - size_t n_utf16; - - if (unlikely(!utf8)) - return NULL; - - c = utf8; - n_utf16 = 0; - - while (*c) { - len = l_utf8_get_codepoint(c, 4, &wc); - if (len < 0) - return NULL; - - if (wc < 0x10000) - n_utf16 += 1; - else - n_utf16 += 2; - - c += len; - } - - utf16 = l_malloc((n_utf16 + 1) * 2); - c = utf8; - n_utf16 = 0; - - while (*c) { - len = l_utf8_get_codepoint(c, 4, &wc); - - if (wc >= 0x10000) { - utf16[n_utf16++] = (wc - 0x1000) / 0x400 + 0xd800; - utf16[n_utf16++] = (wc - 0x1000) % 0x400 + 0xdc00; - } else - utf16[n_utf16++] = wc; - - c += len; - } - - utf16[n_utf16] = 0; - - if (out_size) - *out_size = (n_utf16 + 1) * 2; - - return utf16; -} - -/** - * l_utf8_from_ucs2be: - * @ucs2be: Array of UCS2 characters in big-endian format - * @ucs2be_size: The size of the @ucs2 array in bytes. Must be a multiple of 2. - * - * Returns: A newly-allocated buffer containing UCS2BE encoded string converted - * to UTF8. The UTF8 string will always be null terminated, even if the - * original UCS2BE string was not. - **/ -LIB_EXPORT char *l_utf8_from_ucs2be(const void *ucs2be, ssize_t ucs2be_size) -{ - char *utf8; - size_t utf8_len = 0; - ssize_t i = 0; - uint16_t in; - - if (unlikely(ucs2be_size % 2)) - return NULL; - - while (ucs2be_size < 0 || i < ucs2be_size) { - in = l_get_be16(ucs2be + i); - - if (!in) - break; - - if (in >= 0xd800 && in < 0xe000) - return NULL; - - if (!valid_unicode(in)) - return NULL; - - utf8_len += utf8_length(in); - i += 2; - } - - utf8 = l_malloc(utf8_len + 1); - utf8_len = 0; - i = 0; - - while (ucs2be_size < 0 || i < ucs2be_size) { - in = l_get_be16(ucs2be + i); - - if (!in) - break; - - utf8_len += l_utf8_from_wchar(in, utf8 + utf8_len); - i += 2; - } - - utf8[utf8_len] = '\0'; - - return utf8; -} - -/** - * l_utf8_to_ucs2be: - * @utf8: UTF8 formatted string - * @out_size: The size in bytes of the converted ucs2be string - * - * Converts a UTF8 formatted string to UCS2BE. It is assumed that the string - * is valid UTF8 and no sanity checking is performed. - * - * Returns: A newly-allocated buffer containing UTF8 encoded string converted - * to UCS2BE. The UCS2BE string will always be null terminated. - **/ -LIB_EXPORT void *l_utf8_to_ucs2be(const char *utf8, size_t *out_size) -{ - const char *c; - wchar_t wc; - int len; - uint16_t *ucs2be; - size_t n_ucs2be; - - if (unlikely(!utf8)) - return NULL; - - c = utf8; - n_ucs2be = 0; - - while (*c) { - len = l_utf8_get_codepoint(c, 4, &wc); - if (len < 0) - return NULL; - - if (wc >= 0x10000) - return NULL; - - n_ucs2be += 1; - c += len; - } - - ucs2be = l_malloc((n_ucs2be + 1) * 2); - c = utf8; - n_ucs2be = 0; - - while (*c) { - len = l_utf8_get_codepoint(c, 4, &wc); - ucs2be[n_ucs2be++] = L_CPU_TO_BE16(wc); - c += len; - } - - ucs2be[n_ucs2be] = 0; - - if (out_size) - *out_size = (n_ucs2be + 1) * 2; - - return ucs2be; -} diff --git a/ell/utf8.h b/ell/utf8.h deleted file mode 100644 index c92da60..0000000 --- a/ell/utf8.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_UTF8_H -#define __ELL_UTF8_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern unsigned char l_ascii_table[]; - -enum l_ascii { - L_ASCII_CNTRL = 0x80, - L_ASCII_PRINT = 0x40, - L_ASCII_PUNCT = 0x20, - L_ASCII_SPACE = 0x10, - L_ASCII_XDIGIT = 0x08, - L_ASCII_UPPER = 0x04, - L_ASCII_LOWER = 0x02, - L_ASCII_DIGIT = 0x01, - L_ASCII_ALPHA = L_ASCII_LOWER | L_ASCII_UPPER, - L_ASCII_ALNUM = L_ASCII_ALPHA | L_ASCII_DIGIT, - L_ASCII_GRAPH = L_ASCII_ALNUM | L_ASCII_PUNCT, -}; - -#define l_ascii_isalnum(c) \ - ((l_ascii_table[(unsigned char) (c)] & L_ASCII_ALNUM) != 0) - -#define l_ascii_isalpha(c) \ - ((l_ascii_table[(unsigned char) (c)] & L_ASCII_ALPHA) != 0) - -#define l_ascii_iscntrl(c) \ - ((l_ascii_table[(unsigned char) (c)] & L_ASCII_CNTRL) != 0) - -#define l_ascii_isdigit(c) \ - ((l_ascii_table[(unsigned char) (c)] & L_ASCII_DIGIT) != 0) - -#define l_ascii_isgraph(c) \ - ((l_ascii_table[(unsigned char) (c)] & L_ASCII_GRAPH) != 0) - -#define l_ascii_islower(c) \ - ((l_ascii_table[(unsigned char) (c)] & L_ASCII_LOWER) != 0) - -#define l_ascii_isprint(c) \ - ((l_ascii_table[(unsigned char) (c)] & L_ASCII_PRINT) != 0) - -#define l_ascii_ispunct(c) \ - ((l_ascii_table[(unsigned char) (c)] & L_ASCII_PUNCT) != 0) - -#define l_ascii_isspace(c) \ - ((l_ascii_table[(unsigned char) (c)] & L_ASCII_SPACE) != 0) - -#define l_ascii_isupper(c) \ - ((l_ascii_table[(unsigned char) (c)] & L_ASCII_UPPER) != 0) - -#define l_ascii_isxdigit(c) \ - ((l_ascii_table[(unsigned char) (c)] & L_ASCII_XDIGIT) != 0) - -#if __STDC_VERSION__ <= 199409L -#define inline __inline__ -#endif - -static inline __attribute__ ((always_inline)) - bool l_ascii_isblank(unsigned char c) -{ - if (c == ' ' || c == '\t') - return true; - - return false; -} - -static inline __attribute__ ((always_inline)) bool l_ascii_isascii(int c) -{ - if (c <= 127) - return true; - - return false; -} - -bool l_utf8_validate(const char *src, size_t len, const char **end); -size_t l_utf8_strlen(const char *src); - -int l_utf8_get_codepoint(const char *str, size_t len, wchar_t *cp); -size_t l_utf8_from_wchar(wchar_t c, char *out_buf); - -char *l_utf8_from_utf16(const void *utf16, ssize_t utf16_size); -void *l_utf8_to_utf16(const char *utf8, size_t *out_size); - -char *l_utf8_from_ucs2be(const void *ucs2be, ssize_t ucs2be_size); -void *l_utf8_to_ucs2be(const char *utf8, size_t *out_size); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_UTF8_H */ diff --git a/ell/util.c b/ell/util.c deleted file mode 100644 index 9e90a24..0000000 --- a/ell/util.c +++ /dev/null @@ -1,638 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef TIZEN_FEATURE_BLUEZ_MODIFY -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include - -#include "util.h" -#include "private.h" - -/** - * SECTION:util - * @short_description: Utility functions - * - * Utility functions - */ - -#define STRLOC __FILE__ ":" L_STRINGIFY(__LINE__) - -/** - * l_malloc: - * @size: memory size to allocate - * - * If for any reason the memory allocation fails, then execution will be - * halted via abort(). - * - * In case @size is 0 then #NULL will be returned. - * - * Returns: pointer to allocated memory - **/ -LIB_EXPORT void *l_malloc(size_t size) -{ - if (likely(size)) { - void *ptr; - - ptr = malloc(size); - if (ptr) - return ptr; - - fprintf(stderr, "%s:%s(): failed to allocate %zd bytes\n", - STRLOC, __func__, size); - abort(); - } - - return NULL; -} - -/** - * l_realloc: - * @mem: previously allocated memory, or NULL - * @size: memory size to allocate - * - * If for any reason the memory allocation fails, then execution will be - * halted via abort(). - * - * In case @mem is NULL, this function acts like l_malloc. - * In case @size is 0 then #NULL will be returned. - * - * Returns: pointer to allocated memory - **/ -LIB_EXPORT void *l_realloc(void *mem, size_t size) -{ - if (likely(size)) { - void *ptr; - - ptr = realloc(mem, size); - if (ptr) - return ptr; - - fprintf(stderr, "%s:%s(): failed to re-allocate %zd bytes\n", - STRLOC, __func__, size); - abort(); - } else - l_free(mem); - - return NULL; -} - -/** - * l_memdup: - * @mem: pointer to memory you want to duplicate - * @size: memory size - * - * If for any reason the memory allocation fails, then execution will be - * halted via abort(). - * - * In case @size is 0 then #NULL will be returned. - * - * Returns: pointer to duplicated memory buffer - **/ -LIB_EXPORT void *l_memdup(const void *mem, size_t size) -{ - void *ptr; - - ptr = l_malloc(size); - - memcpy(ptr, mem, size); - - return ptr; -} - -/** - * l_free: - * @ptr: memory pointer - * - * Free the allocated memory area. - **/ -LIB_EXPORT void l_free(void *ptr) -{ - free(ptr); -} - -/** - * l_strdup: - * @str: string pointer - * - * Allocates and duplicates sring - * - * Returns: a newly allocated string - **/ -LIB_EXPORT char *l_strdup(const char *str) -{ - if (likely(str)) { - char *tmp; - - tmp = strdup(str); - if (tmp) - return tmp; - - fprintf(stderr, "%s:%s(): failed to allocate string\n", - STRLOC, __func__); - abort(); - } - - return NULL; -} - -/** - * l_strndup: - * @str: string pointer - * @max: Maximum number of characters to copy - * - * Allocates and duplicates sring. If the string is longer than @max - * characters, only @max are copied and a null terminating character - * is added. - * - * Returns: a newly allocated string - **/ -LIB_EXPORT char *l_strndup(const char *str, size_t max) -{ - if (likely(str)) { - char *tmp; - - tmp = strndup(str, max); - if (tmp) - return tmp; - - fprintf(stderr, "%s:%s(): failed to allocate string\n", - STRLOC, __func__); - abort(); - } - - return NULL; -} - -/** - * l_strdup_printf: - * @format: string format - * @...: parameters to insert into format string - * - * Returns: a newly allocated string - **/ -LIB_EXPORT char *l_strdup_printf(const char *format, ...) -{ - va_list args; - char *str; - int len; - - va_start(args, format); - len = vasprintf(&str, format, args); - va_end(args); - - if (len < 0) { - fprintf(stderr, "%s:%s(): failed to allocate string\n", - STRLOC, __func__); - abort(); - - return NULL; - } - - return str; -} - -/** - * l_strdup_vprintf: - * @format: string format - * @args: parameters to insert into format string - * - * Returns: a newly allocated string - **/ -LIB_EXPORT char *l_strdup_vprintf(const char *format, va_list args) -{ - char *str; - int len; - - len = vasprintf(&str, format, args); - - if (len < 0) { - fprintf(stderr, "%s:%s(): failed to allocate string\n", - STRLOC, __func__); - abort(); - - return NULL; - } - - return str; -} - -/** - * l_strlcpy: - * @dst: Destination buffer for string - * @src: Source buffer containing null-terminated string to copy - * @len: Maximum destination buffer space to use - * - * Copies a string from the @src buffer to the @dst buffer, using no - * more than @len bytes in @dst. @dst is guaranteed to be - * null-terminated. The caller can determine if the copy was truncated by - * checking if the return value is greater than or equal to @len. - * - * NOTE: Passing in a NULL string results in a no-op - * - * Returns: The length of the @src string, not including the null - * terminator. - */ -LIB_EXPORT size_t l_strlcpy(char *dst, const char *src, size_t len) -{ - size_t src_len = src ? strlen(src) : 0; - - if (!src) - goto done; - - if (len) { - if (src_len < len) { - len = src_len + 1; - } else { - len -= 1; - dst[len] = '\0'; - } - - memcpy(dst, src, len); - } - -done: - return src_len; -} - -/** - * l_str_has_prefix: - * @str: A string to be examined - * @delim: Prefix string - * - * Determines if the string given by @str is prefixed by string given by - * @prefix. - * - * Returns: True if @str was prefixed by @prefix. False otherwise. - */ -LIB_EXPORT bool l_str_has_prefix(const char *str, const char *prefix) -{ - size_t str_len; - size_t prefix_len; - - if (unlikely(!str)) - return false; - - if (unlikely(!prefix)) - return false; - - str_len = strlen(str); - prefix_len = strlen(prefix); - - if (str_len < prefix_len) - return false; - - return !strncmp(str, prefix, prefix_len); -} - -/** - * l_str_has_suffix: - * @str: A string to be examined - * @suffix: Suffix string - * - * Determines if the string given by @str ends with the specified @suffix. - * - * Returns: True if @str ends with the specified @suffix. False otherwise. - */ -LIB_EXPORT bool l_str_has_suffix(const char *str, const char *suffix) -{ - size_t str_len; - size_t suffix_len; - size_t len_diff; - - if (unlikely(!str)) - return false; - - if (unlikely(!suffix)) - return false; - - str_len = strlen(str); - suffix_len = strlen(suffix); - - if (str_len < suffix_len) - return false; - - len_diff = str_len - suffix_len; - - return !strcmp(&str[len_diff], suffix); -} - -static char *hexstring_common(const unsigned char *buf, size_t len, - const char hexdigits[static 16]) -{ - char *str; - size_t i; - - if (unlikely(!buf) || unlikely(!len)) - return NULL; - - str = l_malloc(len * 2 + 1); - - for (i = 0; i < len; i++) { - str[(i * 2) + 0] = hexdigits[buf[i] >> 4]; - str[(i * 2) + 1] = hexdigits[buf[i] & 0xf]; - } - - str[len * 2] = '\0'; - - return str; -} - -/** - * l_util_hexstring: - * @buf: buffer pointer - * @len: length of buffer - * - * Returns: a newly allocated hex string. Note that the string will contain - * lower case hex digits a-f. If you require upper case hex digits, use - * @l_util_hexstring_upper - **/ -LIB_EXPORT char *l_util_hexstring(const unsigned char *buf, size_t len) -{ - static const char hexdigits[] = "0123456789abcdef"; - return hexstring_common(buf, len, hexdigits); -} - -/** - * l_util_hexstring_upper: - * @buf: buffer pointer - * @len: length of buffer - * - * Returns: a newly allocated hex string. Note that the string will contain - * upper case hex digits a-f. If you require lower case hex digits, use - * @l_util_hexstring - **/ -LIB_EXPORT char *l_util_hexstring_upper(const unsigned char *buf, size_t len) -{ - static const char hexdigits[] = "0123456789ABCDEF"; - return hexstring_common(buf, len, hexdigits); -} - -/** - * l_util_from_hexstring: - * @str: Null-terminated string containing the hex-encoded bytes - * @out_len: Number of bytes decoded - * - * Returns: a newly allocated byte array. Empty strings are treated as - * an error condition. - **/ -LIB_EXPORT unsigned char *l_util_from_hexstring(const char *str, - size_t *out_len) -{ - size_t i, j; - size_t len; - char c; - unsigned char *buf; - - if (unlikely(!str)) - return NULL; - - for (i = 0; str[i]; i++) { - c = toupper(str[i]); - - if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) - continue; - - return NULL; - } - - if (!i) - return NULL; - - if ((i % 2) != 0) - return NULL; - - len = i; - buf = l_malloc(i >> 1); - - for (i = 0, j = 0; i < len; i++, j++) { - c = toupper(str[i]); - - if (c >= '0' && c <= '9') - buf[j] = c - '0'; - else if (c >= 'A' && c <= 'F') - buf[j] = 10 + c - 'A'; - - i += 1; - - c = toupper(str[i]); - - if (c >= '0' && c <= '9') - buf[j] = buf[j] * 16 + c - '0'; - else if (c >= 'A' && c <= 'F') - buf[j] = buf[j] * 16 + 10 + c - 'A'; - } - - if (out_len) - *out_len = j; - - return buf; -} - -static void hexdump(const char dir, const unsigned char *buf, size_t len, - l_util_hexdump_func_t function, void *user_data) -{ - static const char hexdigits[] = "0123456789abcdef"; - char str[68]; - size_t i; - - if (unlikely(!len)) - return; - - str[0] = dir; - - for (i = 0; i < len; i++) { - str[((i % 16) * 3) + 1] = ' '; - str[((i % 16) * 3) + 2] = hexdigits[buf[i] >> 4]; - str[((i % 16) * 3) + 3] = hexdigits[buf[i] & 0xf]; - str[(i % 16) + 51] = isprint(buf[i]) ? buf[i] : '.'; - - if ((i + 1) % 16 == 0) { - str[49] = ' '; - str[50] = ' '; - str[67] = '\0'; - function(str, user_data); - str[0] = ' '; - } - } - - if (i % 16 > 0) { - size_t j; - for (j = (i % 16); j < 16; j++) { - str[(j * 3) + 1] = ' '; - str[(j * 3) + 2] = ' '; - str[(j * 3) + 3] = ' '; - str[j + 51] = ' '; - } - str[49] = ' '; - str[50] = ' '; - str[67] = '\0'; - function(str, user_data); - } -} - -LIB_EXPORT void l_util_hexdump(bool in, const void *buf, size_t len, - l_util_hexdump_func_t function, void *user_data) -{ - if (likely(!function)) - return; - - hexdump(in ? '<' : '>', buf, len, function, user_data); -} - -LIB_EXPORT void l_util_hexdump_two(bool in, const void *buf1, size_t len1, - const void *buf2, size_t len2, - l_util_hexdump_func_t function, void *user_data) -{ - if (likely(!function)) - return; - - hexdump(in ? '<' : '>', buf1, len1, function, user_data); - hexdump(' ', buf2, len2, function, user_data); -} - -LIB_EXPORT void l_util_hexdumpv(bool in, const struct iovec *iov, - size_t n_iov, - l_util_hexdump_func_t function, - void *user_data) -{ - static const char hexdigits[] = "0123456789abcdef"; - char str[68]; - size_t i; - size_t len; - size_t c; - const uint8_t *buf; - - if (unlikely(!iov || !n_iov)) - return; - - str[0] = in ? '<' : '>'; - - for (i = 0, len = 0; i < n_iov; i++) - len += iov[i].iov_len; - - c = 0; - buf = iov[0].iov_base; - - for (i = 0; i < len; i++, c++) { - if (c == iov[0].iov_len) { - c = 0; - iov += 1; - buf = iov[0].iov_base; - } - - str[((i % 16) * 3) + 1] = ' '; - str[((i % 16) * 3) + 2] = hexdigits[buf[c] >> 4]; - str[((i % 16) * 3) + 3] = hexdigits[buf[c] & 0xf]; - str[(i % 16) + 51] = isprint(buf[c]) ? buf[c] : '.'; - - if ((i + 1) % 16 == 0) { - str[49] = ' '; - str[50] = ' '; - str[67] = '\0'; - function(str, user_data); - str[0] = ' '; - } - } - - if (i % 16 > 0) { - size_t j; - for (j = (i % 16); j < 16; j++) { - str[(j * 3) + 1] = ' '; - str[(j * 3) + 2] = ' '; - str[(j * 3) + 3] = ' '; - str[j + 51] = ' '; - } - str[49] = ' '; - str[50] = ' '; - str[67] = '\0'; - function(str, user_data); - } -} - -LIB_EXPORT void l_util_debug(l_util_hexdump_func_t function, void *user_data, - const char *format, ...) -{ - va_list args; - char *str; - int len; - - if (likely(!function)) - return; - - if (unlikely(!format)) - return; - - va_start(args, format); - len = vasprintf(&str, format, args); - va_end(args); - - if (unlikely(len < 0)) - return; - - function(str, user_data); - - free(str); -} - -/** - * l_util_get_debugfs_path: - * - * Returns: a pointer to mount point of debugfs - **/ -LIB_EXPORT const char *l_util_get_debugfs_path(void) -{ - static char path[PATH_MAX + 1]; - static bool found = false; - char type[100]; - FILE *fp; - - if (found) - return path; - - fp = fopen("/proc/mounts", "r"); - if (!fp) - return NULL; - - while (fscanf(fp, "%*s %" L_STRINGIFY(PATH_MAX) "s %99s %*s %*d %*d\n", - path, type) == 2) { - if (!strcmp(type, "debugfs")) { - found = true; - break; - } - } - - fclose(fp); - - if (!found) - return NULL; - - return path; -} diff --git a/ell/util.h b/ell/util.h deleted file mode 100644 index 4f20ef0..0000000 --- a/ell/util.h +++ /dev/null @@ -1,318 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_UTIL_H -#define __ELL_UTIL_H - -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define l_container_of(ptr, type, member) ({ \ - const __typeof__(((type *) 0)->member) *__mptr = (ptr); \ - (type *)((char *) __mptr - offsetof(type, member)); \ - }) - -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) - -#define L_STRINGIFY(val) L_STRINGIFY_ARG(val) -#define L_STRINGIFY_ARG(contents) #contents - -#define L_WARN_ON(condition) __extension__ ({ \ - bool r = !!(condition); \ - if (unlikely(r)) \ - l_warn("WARNING: %s:%s() condition %s failed", \ - __FILE__, __func__, \ - #condition); \ - unlikely(r); \ - }) - -#define L_PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p))) -#define L_UINT_TO_PTR(u) ((void *) ((uintptr_t) (u))) - -#define L_PTR_TO_INT(p) ((int) ((intptr_t) (p))) -#define L_INT_TO_PTR(u) ((void *) ((intptr_t) (u))) - -#define L_GET_UNALIGNED(ptr) __extension__ \ -({ \ - struct __attribute__((packed)) { \ - __typeof__(*(ptr)) __v; \ - } *__p = (__typeof__(__p)) (ptr); \ - __p->__v; \ -}) - -#define L_PUT_UNALIGNED(val, ptr) \ -do { \ - struct __attribute__((packed)) { \ - __typeof__(*(ptr)) __v; \ - } *__p = (__typeof__(__p)) (ptr); \ - __p->__v = (val); \ -} while(0) - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define L_LE16_TO_CPU(val) (val) -#define L_LE32_TO_CPU(val) (val) -#define L_LE64_TO_CPU(val) (val) -#define L_CPU_TO_LE16(val) (val) -#define L_CPU_TO_LE32(val) (val) -#define L_CPU_TO_LE64(val) (val) -#define L_BE16_TO_CPU(val) bswap_16(val) -#define L_BE32_TO_CPU(val) bswap_32(val) -#define L_BE64_TO_CPU(val) bswap_64(val) -#define L_CPU_TO_BE16(val) bswap_16(val) -#define L_CPU_TO_BE32(val) bswap_32(val) -#define L_CPU_TO_BE64(val) bswap_64(val) -#elif __BYTE_ORDER == __BIG_ENDIAN -#define L_LE16_TO_CPU(val) bswap_16(val) -#define L_LE32_TO_CPU(val) bswap_32(val) -#define L_LE64_TO_CPU(val) bswap_64(val) -#define L_CPU_TO_LE16(val) bswap_16(val) -#define L_CPU_TO_LE32(val) bswap_32(val) -#define L_CPU_TO_LE64(val) bswap_64(val) -#define L_BE16_TO_CPU(val) (val) -#define L_BE32_TO_CPU(val) (val) -#define L_BE64_TO_CPU(val) (val) -#define L_CPU_TO_BE16(val) (val) -#define L_CPU_TO_BE32(val) (val) -#define L_CPU_TO_BE64(val) (val) -#else -#error "Unknown byte order" -#endif - -#if __STDC_VERSION__ <= 199409L -#define inline __inline__ -#endif - -static inline uint8_t l_get_u8(const void *ptr) -{ - return *((const uint8_t *) ptr); -} - -static inline void l_put_u8(uint8_t val, void *ptr) -{ - *((uint8_t *) ptr) = val; -} - -static inline uint16_t l_get_u16(const void *ptr) -{ - return L_GET_UNALIGNED((const uint16_t *) ptr); -} - -static inline void l_put_u16(uint16_t val, void *ptr) -{ - L_PUT_UNALIGNED(val, (uint16_t *) ptr); -} - -static inline uint32_t l_get_u32(const void *ptr) -{ - return L_GET_UNALIGNED((const uint32_t *) ptr); -} - -static inline void l_put_u32(uint32_t val, void *ptr) -{ - L_PUT_UNALIGNED(val, (uint32_t *) ptr); -} - -static inline uint64_t l_get_u64(const void *ptr) -{ - return L_GET_UNALIGNED((const uint64_t *) ptr); -} - -static inline void l_put_u64(uint64_t val, void *ptr) -{ - L_PUT_UNALIGNED(val, (uint64_t *) ptr); -} - -static inline int16_t l_get_s16(const void *ptr) -{ - return L_GET_UNALIGNED((const int16_t *) ptr); -} - -static inline int32_t l_get_s32(const void *ptr) -{ - return L_GET_UNALIGNED((const int32_t *) ptr); -} - -static inline int64_t l_get_s64(const void *ptr) -{ - return L_GET_UNALIGNED((const int64_t *) ptr); -} - -static inline uint16_t l_get_le16(const void *ptr) -{ - return L_LE16_TO_CPU(L_GET_UNALIGNED((const uint16_t *) ptr)); -} - -static inline uint16_t l_get_be16(const void *ptr) -{ - return L_BE16_TO_CPU(L_GET_UNALIGNED((const uint16_t *) ptr)); -} - -static inline uint32_t l_get_le32(const void *ptr) -{ - return L_LE32_TO_CPU(L_GET_UNALIGNED((const uint32_t *) ptr)); -} - -static inline uint32_t l_get_be32(const void *ptr) -{ - return L_BE32_TO_CPU(L_GET_UNALIGNED((const uint32_t *) ptr)); -} - -static inline uint64_t l_get_le64(const void *ptr) -{ - return L_LE64_TO_CPU(L_GET_UNALIGNED((const uint64_t *) ptr)); -} - -static inline uint64_t l_get_be64(const void *ptr) -{ - return L_BE64_TO_CPU(L_GET_UNALIGNED((const uint64_t *) ptr)); -} - -static inline void l_put_le16(uint16_t val, void *ptr) -{ - L_PUT_UNALIGNED(L_CPU_TO_LE16(val), (uint16_t *) ptr); -} - -static inline void l_put_be16(uint16_t val, const void *ptr) -{ - L_PUT_UNALIGNED(L_CPU_TO_BE16(val), (uint16_t *) ptr); -} - -static inline void l_put_le32(uint32_t val, void *ptr) -{ - L_PUT_UNALIGNED(L_CPU_TO_LE32(val), (uint32_t *) ptr); -} - -static inline void l_put_be32(uint32_t val, void *ptr) -{ - L_PUT_UNALIGNED(L_CPU_TO_BE32(val), (uint32_t *) ptr); -} - -static inline void l_put_le64(uint64_t val, void *ptr) -{ - L_PUT_UNALIGNED(L_CPU_TO_LE64(val), (uint64_t *) ptr); -} - -static inline void l_put_be64(uint64_t val, void *ptr) -{ - L_PUT_UNALIGNED(L_CPU_TO_BE64(val), (uint64_t *) ptr); -} - -#define L_AUTO_CLEANUP_VAR(vartype,varname,destroy) \ - vartype varname __attribute__((cleanup(destroy))) - -#define L_AUTO_FREE_VAR(vartype,varname) \ - vartype varname __attribute__((cleanup(auto_free))) - -#define L_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -void *l_malloc(size_t size) __attribute__ ((warn_unused_result, malloc)); -void *l_memdup(const void *mem, size_t size) - __attribute__ ((warn_unused_result, malloc)); -void l_free(void *ptr); - -void *l_realloc(void *mem, size_t size) - __attribute__ ((warn_unused_result, malloc)); - -static inline void auto_free(void *a) -{ - void **p = (void **)a; - l_free(*p); -} - -static inline size_t minsize(size_t a, size_t b) -{ - if (a <= b) - return a; - - return b; -} - -/** - * l_new: - * @type: type of structure - * @count: amount of structures - * - * Returns: pointer to allocated memory - **/ -#define l_new(type, count) \ - (type *) (__extension__ ({ \ - size_t __n = (size_t) (count); \ - size_t __s = sizeof(type); \ - void *__p; \ - __p = l_malloc(__n * __s); \ - memset(__p, 0, __n * __s); \ - __p; \ - })) - -char *l_strdup(const char *str); -char *l_strndup(const char *str, size_t max); -char *l_strdup_printf(const char *format, ...) - __attribute__((format(printf, 1, 2))); -char *l_strdup_vprintf(const char *format, va_list args); - -size_t l_strlcpy(char* dst, const char *src, size_t len); - -bool l_str_has_prefix(const char *str, const char *prefix); -bool l_str_has_suffix(const char *str, const char *suffix); - -char *l_util_hexstring(const unsigned char *buf, size_t len); -char *l_util_hexstring_upper(const unsigned char *buf, size_t len); -unsigned char *l_util_from_hexstring(const char *str, size_t *out_len); - -typedef void (*l_util_hexdump_func_t) (const char *str, void *user_data); - -void l_util_hexdump(bool in, const void *buf, size_t len, - l_util_hexdump_func_t function, void *user_data); -void l_util_hexdump_two(bool in, const void *buf1, size_t len1, - const void *buf2, size_t len2, - l_util_hexdump_func_t function, void *user_data); -void l_util_hexdumpv(bool in, const struct iovec *iov, size_t n_iov, - l_util_hexdump_func_t function, - void *user_data); -void l_util_debug(l_util_hexdump_func_t function, void *user_data, - const char *format, ...) - __attribute__((format(printf, 3, 4))); - -const char *l_util_get_debugfs_path(void); - -#define L_TFR(expression) \ - (__extension__ \ - ({ long int __result; \ - do __result = (long int) (expression); \ - while (__result == -1L && errno == EINTR); \ - __result; })) - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_UTIL_H */ diff --git a/ell/uuid.c b/ell/uuid.c deleted file mode 100644 index de54015..0000000 --- a/ell/uuid.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE -#include - -#include "checksum.h" -#include "random.h" -#include "private.h" -#include "uuid.h" - -const uint8_t L_UUID_NAMESPACE_DNS[16] = { - 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, -}; - -const uint8_t L_UUID_NAMESPACE_URL[16] = { - 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, -}; - -const uint8_t L_UUID_NAMESPACE_OID[16] = { - 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, -}; - -const uint8_t L_UUID_NAMESPACE_X500[16] = { - 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, -}; - -/* RFC 4122, Section 4.3 */ -static bool name_from_namespace(int version, const uint8_t nsid[16], - const void *name, - size_t name_size, uint8_t out_uuid[16]) -{ - enum l_checksum_type type; - struct l_checksum *hash; - struct iovec iov[2]; - - if (unlikely(!out_uuid)) - return false; - - switch (version) { - case 3: - type = L_CHECKSUM_MD5; - break; - case 5: - type = L_CHECKSUM_SHA1; - break; - default: - return false; - } - - hash = l_checksum_new(type); - if (!hash) - return false; - - iov[0].iov_base = (void *) nsid; - iov[0].iov_len = 16; - iov[1].iov_base = (void *) name; - iov[1].iov_len = name_size; - - /* Compute the hash of the name space ID concatenated with the name. */ - l_checksum_updatev(hash, iov, 2); - - /* o Set octets zero through 3 of the time_low field to octets zero - * through 3 of the hash. - * - * o Set octets zero and one of the time_mid field to octets 4 and 5 of - * the hash. - * - * o Set octets zero and one of the time_hi_and_version field to octets - * 6 and 7 of the hash. - * o Set the four most significant bits (bits 12 through 15) of the - * time_hi_and_version field to the appropriate 4-bit version number - * from Section 4.1.3. - * - * o Set the clock_seq_hi_and_reserved field to octet 8 of the hash. - * o Set the two most significant bits (bits 6 and 7) of the - * clock_seq_hi_and_reserved to zero and one, respectively. - * - * o Set the clock_seq_low field to octet 9 of the hash. - * - * o Set octets zero through five of the node field to octets 10 - * through 15 of the hash. - */ - - l_checksum_get_digest(hash, out_uuid, 16); - - /* Set 4 MSB bits of time_hi_and_version field */ - out_uuid[6] &= 0x0f; - out_uuid[6] |= version << 4; - - /* Set 2 MSB of clock_seq_hi_and_reserved to 10 */ - out_uuid[8] &= 0x3f; - out_uuid[8] |= 0x80; - - l_checksum_free(hash); - - return true; -} - -LIB_EXPORT bool l_uuid_v3(const uint8_t nsid[16], const void *name, - size_t name_size, uint8_t out_uuid[16]) -{ - return name_from_namespace(3, nsid, name, name_size, out_uuid); -} - -LIB_EXPORT bool l_uuid_v5(const uint8_t nsid[16], const void *name, - size_t name_size, uint8_t out_uuid[16]) -{ - return name_from_namespace(5, nsid, name, name_size, out_uuid); -} - -/* RFC 4122, Section 4.4 */ -LIB_EXPORT bool l_uuid_v4(uint8_t out_uuid[16]) -{ - if (unlikely(!out_uuid)) - return false; - - if (!l_getrandom(out_uuid, 16)) - return false; - - /* - * o Set the two most significant bits (bits 6 and 7) of the - * clock_seq_hi_and_reserved to zero and one, respectively. - * - * o Set the four most significant bits (bits 12 through 15) of the - * time_hi_and_version field to the 4-bit version number from - * Section 4.1.3. - * - * o Set all the other bits to randomly (or pseudo-randomly) chosen - * values. - */ - - /* Set 4 MSB bits of time_hi_and_version field */ - out_uuid[6] &= 0x0f; - out_uuid[6] |= 4 << 4; - - /* Set 2 MSB of clock_seq_hi_and_reserved to 10 */ - out_uuid[8] &= 0x3f; - out_uuid[8] |= 0x80; - - return true; -} - -/** - * l_uuid_is_valid: - * @uuid: UUID to check. - * - * Checks whether the given UUID is valid according to RFC 4122. This function - * checks that the version field is set properly and the variant of the UUID - * is set to RFC 4122. - * - * Returns: Whether the UUID is valid - **/ -LIB_EXPORT bool l_uuid_is_valid(const uint8_t uuid[16]) -{ - unsigned int version; - unsigned int variant; - - if (!uuid) - return false; - - variant = uuid[8] >> 6; - if (variant != 2) - return false; - - version = uuid[6] >> 4; - if (version < 1 || version > 5) - return false; - - return true; -} - -LIB_EXPORT enum l_uuid_version l_uuid_get_version(const uint8_t uuid[16]) -{ - unsigned int version; - - version = uuid[6] >> 4; - return version; -} - -LIB_EXPORT bool l_uuid_to_string(const uint8_t uuid[16], - char *dest, size_t dest_size) -{ - int n; - - n = snprintf(dest, dest_size, "%02x%02x%02x%02x-%02x%02x-%02x%02x-" - "%02x%02x-%02x%02x%02x%02x%02x%02x", - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], - uuid[6], uuid[7], - uuid[8], uuid[9], - uuid[10], uuid[11], uuid[12], - uuid[13], uuid[14], uuid[15]); - - if (n < 0 || (size_t) n >= dest_size) - return false; - - return true; -} - -LIB_EXPORT bool l_uuid_from_string(const char *src, uint8_t uuid[16]) -{ - uint8_t buf[16]; - int n; - - /* - * textual representation: 32 hex digits + 4 group separators - */ - if (strlen(src) < 16 * 2 + 4) - return false; - - n = sscanf(src, - "%02hhx%02hhx%02hhx%02hhx-" - "%02hhx%02hhx-" - "%02hhx%02hhx-" - "%02hhx%02hhx-" - "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", - &buf[0], &buf[1], &buf[2], &buf[3], - &buf[4], &buf[5], - &buf[6], &buf[7], - &buf[8], &buf[9], - &buf[10], &buf[11], &buf[12], - &buf[13], &buf[14], &buf[15]); - - if (n != 16) - return false; - - if (!l_uuid_is_valid(buf)) - return false; - - memcpy(uuid, buf, sizeof(buf)); - return true; -} diff --git a/ell/uuid.h b/ell/uuid.h deleted file mode 100644 index cb59b78..0000000 --- a/ell/uuid.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Embedded Linux library - * - * Copyright (C) 2011-2015 Intel Corporation. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __ELL_UUID_H -#define __ELL_UUID_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -enum l_uuid_version { - L_UUID_VERSION_1_TIME = 1, - L_UUID_VERSION_2_DCE = 2, - L_UUID_VERSION_3_MD5 = 3, - L_UUID_VERSION_4_RANDOM = 4, - L_UUID_VERSION_5_SHA1 = 5, -}; - -extern const uint8_t L_UUID_NAMESPACE_DNS[]; -extern const uint8_t L_UUID_NAMESPACE_URL[]; -extern const uint8_t L_UUID_NAMESPACE_OID[]; -extern const uint8_t L_UUID_NAMESPACE_X500[]; - -bool l_uuid_v3(const uint8_t nsid[16], const void *name, size_t name_size, - uint8_t out_uuid[16]); -bool l_uuid_v4(uint8_t out_uuid[16]); -bool l_uuid_v5(const uint8_t nsid[16], const void *name, size_t name_size, - uint8_t out_uuid[16]); - -bool l_uuid_is_valid(const uint8_t uuid[16]); -enum l_uuid_version l_uuid_get_version(const uint8_t uuid[16]); - -bool l_uuid_to_string(const uint8_t uuid[16], char *dest, size_t dest_size); -bool l_uuid_from_string(const char *src, uint8_t uuid[16]); - -#ifdef __cplusplus -} -#endif - -#endif /* __ELL_UTIL_H */ diff --git a/packaging/bluez.spec b/packaging/bluez.spec index f737e92..c031948 100755 --- a/packaging/bluez.spec +++ b/packaging/bluez.spec @@ -31,6 +31,7 @@ BuildRequires: pkgconfig(dbus-1) BuildRequires: pkgconfig(iniparser) BuildRequires: pkgconfig(libxml-2.0) BuildRequires: pkgconfig(json-c) +BuildRequires: pkgconfig(ell) #BuildRequires: pkgconfig(glib-2.0) #BuildRequires: pkgconfig(ncurses) #BuildRequires: flex @@ -226,7 +227,8 @@ export CFLAGS+=" -DARCH64" --enable-experimental \ --enable-autopyypair=no \ --enable-tizenunusedplugin=no \ - --disable-crypto-tests + --disable-crypto-tests \ + --enable-external-ell make %{?_smp_mflags} all V=1 @@ -291,7 +293,8 @@ export CFLAGS+=" -DARCH64" --enable-hid=yes \ --enable-bredr=yes \ --enable-tizenunusedplugin=no \ - --disable-crypto-tests + --disable-crypto-tests \ + --enable-external-ell make %{?_smp_mflags} all V=1 @@ -359,7 +362,8 @@ export CFLAGS+=" -DARCH64" --enable-hid=yes \ --enable-bredr=yes \ --enable-tizenunusedplugin=no \ - --disable-crypto-tests + --disable-crypto-tests \ + --enable-external-ell make %{?_smp_mflags} all V=1 -- 2.7.4