+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <stdint.h>
-
-#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;
-}
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- *
- * 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);
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <string.h>
-#include <stdio.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stddef.h>
-
-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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <unistd.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <stdio.h>
-
-#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 <linux/types.h>
-#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 <linux/if_alg.h>
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-#include <stdint.h>
-#include <sys/uio.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <unistd.h>
-#include <errno.h>
-#include <sys/socket.h>
-#include <alloca.h>
-
-#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 <linux/types.h>
-#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 <linux/if_alg.h>
-#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);
-}
+++ /dev/null
-/*
- *
- * 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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <stdlib.h>
-#include <stdio.h>
-
-#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);
-}
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <stdio.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#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);
-}
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <stdlib.h>
-#include <stdio.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <endian.h>
-
-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);
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <stdarg.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#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 "<!DOCTYPE node PUBLIC \""XML_ID"\"\n\""XML_DTD"\">\n"
-
-static const char *static_introspectable =
- "\t<interface name=\"org.freedesktop.DBus.Introspectable\">\n"
- "\t\t<method name=\"Introspect\">\n"
- "\t\t\t<arg name=\"xml\" type=\"s\" direction=\"out\"/>\n"
- "\t\t</method>\n\t</interface>\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<method name=\"%s\">\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<arg name=\"%s\" "
- "type=\"%.*s\" direction=\"in\"/>\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<arg name=\"%s\" "
- "type=\"%.*s\" direction=\"out\"/>\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<annotation name=\""
- "org.freedesktop.DBus.Deprecated\" "
- "value=\"true\"/>\n");
-
- if (info->flags & L_DBUS_METHOD_FLAG_NOREPLY)
- l_string_append(buf, "\t\t\t<annotation name=\""
- "org.freedesktop.DBus.Method.NoReply\" "
- "value=\"true\"/>\n");
-
- l_string_append(buf, "\t\t</method>\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<signal name=\"%s\">\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<arg name=\"%s\" "
- "type=\"%.*s\"/>\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<annotation name=\""
- "org.freedesktop.DBus.Deprecated\" "
- "value=\"true\"/>\n");
-
- l_string_append(buf, "\t\t</signal>\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\t<property name=\"%s\" type=\"%s\" ",
- info->metainfo, 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<annotation name=\""
- "org.freedesktop.DBus.Deprecated\" "
- "value=\"true\"/>\n");
- l_string_append(buf, "\t\t</property>\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<interface name=\"%s\">\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</interface>\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, "<node>\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<node name=\"%s\"/>\n",
- child->subpath);
- }
-
- l_string_append(buf, "</node>\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");
-}
+++ /dev/null
-/*
- *
- * 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 <stdint.h>
-#include <stdbool.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <stdbool.h>
-#include <stdint.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <errno.h>
-
-#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);
-}
+++ /dev/null
-/*
- *
- * 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 <stdint.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdarg.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#include <linux/types.h>
-#include <netinet/ip.h>
-#include <arpa/inet.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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);
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <linux/types.h>
-#include <sys/uio.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stddef.h>
-#include <net/if.h>
-#include <linux/if_packet.h>
-#include <netinet/udp.h>
-#include <netinet/ip.h>
-#include <linux/if_ether.h>
-#include <linux/filter.h>
-#include <net/if_arp.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#include <netinet/ip.h>
-#include <net/ethernet.h>
-#include <linux/types.h>
-#include <net/if_arp.h>
-#include <errno.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-
-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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <unistd.h>
-#include <dirent.h>
-#include <limits.h>
-#include <sys/inotify.h>
-
-#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);
-}
+++ /dev/null
-/*
- *
- * 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 */
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#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));
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-#include <stdint.h>
-
-#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);
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-
-#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 y<p2 and p-y otherwise."
- */
-void _ecc_calculate_p2(const struct l_ecc_curve *curve, uint64_t *p2)
-{
- uint64_t one[L_ECC_MAX_DIGITS] = { 1 };
-
- _vli_mod_sub(p2, curve->p, 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));
-}
+++ /dev/null
-/*
- *
- * 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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#include <stdint.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 */
+++ /dev/null
-/*
- *
- * 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 <ell/util.h>
-#include <ell/test.h>
-#include <ell/strv.h>
-#include <ell/utf8.h>
-#include <ell/queue.h>
-#include <ell/hashmap.h>
-#include <ell/string.h>
-#include <ell/main.h>
-#include <ell/idle.h>
-#include <ell/signal.h>
-#include <ell/timeout.h>
-#include <ell/io.h>
-#include <ell/ringbuf.h>
-#include <ell/log.h>
-#include <ell/plugin.h>
-#include <ell/checksum.h>
-#include <ell/settings.h>
-#include <ell/hwdb.h>
-#include <ell/cipher.h>
-#include <ell/random.h>
-#include <ell/uintset.h>
-#include <ell/base64.h>
-#include <ell/pem.h>
-#include <ell/tls.h>
-#include <ell/uuid.h>
-#include <ell/key.h>
-#include <ell/pkcs5.h>
-#include <ell/file.h>
-#include <ell/dir.h>
-#include <ell/net.h>
-#include <ell/netlink.h>
-#include <ell/genl.h>
-#include <ell/dbus.h>
-#include <ell/dbus-service.h>
-#include <ell/dbus-client.h>
-#include <ell/dhcp.h>
-#include <ell/cert.h>
-#include <ell/ecc.h>
-#include <ell/ecdh.h>
-#include <ell/time.h>
-#include <ell/gpio.h>
-#include <ell/path.h>
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 */
+++ /dev/null
-/*
- *
- * 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);
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#include <errno.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <linux/genetlink.h>
-
-#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);
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <linux/gpio.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdint.h>
-#include <stdbool.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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);
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <stdbool.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdarg.h>
-#include <endian.h>
-#include <limits.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <alloca.h>
-#include <fnmatch.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdarg.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#include <unistd.h>
-
-#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);
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#include <errno.h>
-#include <unistd.h>
-#include <sys/epoll.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <unistd.h>
-#include <stdint.h>
-#include <sys/syscall.h>
-#include <linux/keyctl.h>
-#include <errno.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stddef.h>
-#include <stdbool.h>
-
-#include <ell/checksum.h>
-
-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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <fnmatch.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#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);
-}
+++ /dev/null
-/*
- *
- * 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 <stdarg.h>
-#include <stdbool.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <limits.h>
-#include <signal.h>
-#include <sys/epoll.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-#include <stdint.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <sys/syscall.h>
-
-#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
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#include <sys/socket.h>
-#include <linux/if_arp.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-
-#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);
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-#include <stdint.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#include <unistd.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-#include <stdint.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <sys/types.h>
-
-const char *pem_next(const void *buf, size_t buf_len, char **type_label,
- size_t *base64_len,
- const char **endp, bool strict);
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <strings.h>
-
-#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);
-}
+++ /dev/null
-/*
- *
- * 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 */
+++ /dev/null
-/*
- *
- * 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);
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <unistd.h>
-#include <stdarg.h>
-#include <string.h>
-#include <strings.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-#include <stdint.h>
-
-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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <dlfcn.h>
-#include <stdlib.h>
-#include <glob.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 */
+++ /dev/null
-/*
- *
- * 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 <stdint.h>
-#include <errno.h>
-
-#include <ell/util.h>
-
-#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);
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/syscall.h>
-
-#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();
-}
+++ /dev/null
-/*
- *
- * 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 <stddef.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <string.h>
-#include <sys/uio.h>
-#include <sys/param.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdlib.h>
-#include <stdarg.h>
-#include <stdbool.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#if __STDC_VERSION__ <= 199409L
-#define _DEFAULT_SOURCE /* for strto{u}ll() */
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-#include <stddef.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/epoll.h>
-#include <sys/signalfd.h>
-
-#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);
-}
+++ /dev/null
-/*
- *
- * 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 <stdint.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <string.h>
-#include <stdint.h>
-
-void _siphash24(uint8_t out[8], const uint8_t *in, size_t inlen,
- const uint8_t k[16]);
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#include "siphash-private.h"
-
-/*
- * Based on public domain SipHash reference C implementation
- *
- * Written in 2012 by
- * Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
- * Daniel J. Bernstein <djb@cr.yp.to>
- *
- */
-
-#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);
-}
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#include <stdio.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdarg.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <string.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <time.h>
-
-#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.
- **/
+++ /dev/null
-/*
- *
- * 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 <stdint.h>
-#include <stdbool.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <time.h>
-#include <limits.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 */
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#include <errno.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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);
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <alloca.h>
-
-#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;
- }
-}
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <strings.h>
-
-#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,
-};
+++ /dev/null
-/*
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <time.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <stdio.h>
-#include <strings.h>
-
-#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;
-}
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <limits.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-
-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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#include <stdio.h>
-#include <wchar.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-#include <wchar.h>
-#include <sys/types.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#ifndef TIZEN_FEATURE_BLUEZ_MODIFY
-#define _GNU_SOURCE
-#endif
-#include <stdio.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <limits.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <string.h>
-#include <stdbool.h>
-#include <stdarg.h>
-#include <inttypes.h>
-#include <endian.h>
-#include <byteswap.h>
-#include <sys/uio.h>
-
-#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 */
+++ /dev/null
-/*
- *
- * 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 <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <stdio.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * 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 <stdbool.h>
-#include <inttypes.h>
-
-#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 */
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
--enable-experimental \
--enable-autopyypair=no \
--enable-tizenunusedplugin=no \
- --disable-crypto-tests
+ --disable-crypto-tests \
+ --enable-external-ell
make %{?_smp_mflags} all V=1
--enable-hid=yes \
--enable-bredr=yes \
--enable-tizenunusedplugin=no \
- --disable-crypto-tests
+ --disable-crypto-tests \
+ --enable-external-ell
make %{?_smp_mflags} all V=1
--enable-hid=yes \
--enable-bredr=yes \
--enable-tizenunusedplugin=no \
- --disable-crypto-tests
+ --disable-crypto-tests \
+ --enable-external-ell
make %{?_smp_mflags} all V=1