diff options
38 files changed, 4735 insertions, 3 deletions
diff --git a/configure.ac b/configure.ac index 744e34e..7797c3d 100644 --- a/configure.ac +++ b/configure.ac @@ -108,6 +108,7 @@ libnl-3.0.pc libnl-route-3.0.pc libnl-genl-3.0.pc libnl-nf-3.0.pc +libnl-dect-3.0.pc libnl-cli-3.0.pc lib/Makefile include/Makefile diff --git a/include/Makefile.am b/include/Makefile.am index 3488c52..e4fe6a4 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -17,6 +17,12 @@ nobase_libnlinclude_HEADERS = \ netlink/netfilter/nfnl.h \ netlink/netfilter/queue.h \ netlink/netfilter/queue_msg.h \ + netlink/dect/ari.h \ + netlink/dect/cell.h \ + netlink/dect/cluster.h \ + netlink/dect/dect.h \ + netlink/dect/llme.h \ + netlink/dect/transceiver.h \ netlink/addr.h \ netlink/attr.h \ netlink/cache.h \ diff --git a/include/linux/dect.h b/include/linux/dect.h new file mode 100644 index 0000000..e458a9c --- /dev/null +++ b/include/linux/dect.h @@ -0,0 +1,206 @@ +#ifndef _LINUX_DECT_H +#define _LINUX_DECT_H + +#define DECTNAMSIZ 16 + +#include <linux/types.h> +#include <linux/socket.h> + +/* these have to be macros in order to be usable for module aliases */ +#define DECT_RAW 0 /* raw frames */ +#define DECT_B_SAP 1 /* DLC Broadcast Service */ +#define DECT_S_SAP 2 /* DLC Data Link Service */ +#define DECT_LU1_SAP 3 /* LU1 sockets */ +#define DECT_PROTO_NUM 4 + +/** + * struct sockaddr_dect + * + * @dect_family: address family (AF_DECT) + * @dect_index: cluster index + */ +struct sockaddr_dect { + sa_family_t dect_family; + int dect_index; +}; + +/* raw sockets */ + +#define DECT_RAW_AUXDATA 0 + +/** + * struct dect_raw_auxdata - raw socket auxiliary frame data + * + * @mfn: multi-frame number + * @frame: frame number + * @slot: slot numer + * @rssi: receive signal strength indicator + */ +struct dect_raw_auxdata { + __u32 mfn; + __u8 frame; + __u8 slot; + __u8 rssi; +}; + +#define DECT_BSAP_AUXDATA 0 + +/** + * struct dect_bsap_auxdata + * + * @long_page: message contains a long page + */ +struct dect_bsap_auxdata { + __u8 long_page; +}; + +/** + * enum dect_sapis - S SAP Identifier + * + * @DECT_SAPI_CO_SIGNALLING: connection oriented signalling + * @DECT_SAPI_CL_SIGNALLING: connectionless signalling + * @DECT_SAPI_ANY: wildcard + */ +enum dect_sapis { + DECT_SAPI_CO_SIGNALLING = 0, + DECT_SAPI_CL_SIGNALLING = 3, + DECT_SAPI_ANY = 7, +}; + +/** + * enum dect_llns - Logical Link Numbers + * + * @DECT_LLN_CLASS_U: Class U operation + * @DECT_LLN_CLASS_A: Class A operation + * @DECT_LLN_ASSIGNABLE*: Assignable LLN (class B operation) + * @DECT_LLN_UNASSIGNED: LLN unassigned (class B operation + * @DECT_LLN_ANY: wildcard + */ +enum dect_llns { + DECT_LLN_CLASS_U = 0, + DECT_LLN_CLASS_A = 1, + DECT_LLN_ASSIGNABLE_MIN = 2, + DECT_LLN_ASSIGNABLE_MAX = 6, + DECT_LLN_UNASSIGNED = 7, + DECT_LLN_ANY = 15, +}; + +/** + * struct sockaddr_dect_ssap + * + * @dect_family: family (AF_DECT) + * @dect_lln: logical link number + * @dect_sapi: service access point identifier + * @dect_class: class A/B + * @dect_index: cluster index + * @dect_ari: ARI + * @dect_pmid: PMID + * @dect_lcn: logical connection number + */ +struct sockaddr_dect_ssap { + sa_family_t dect_family; + __u8 dect_lln:4, + dect_sapi:3; + __u8 dect_class; + int dect_index; + __u64 dect_ari:40, + dect_pmid:20, + dect_lcn:3; +}; + +/* S-SAP primitives */ +#define DECT_DL_ENC_KEY 1 +#define DECT_DL_ENCRYPT 2 +#define DECT_DL_MAC_CONN_PARAMS 3 + +enum dect_cipher_states { + DECT_CIPHER_DISABLED, + DECT_CIPHER_ENABLED, +}; + +/** + * enum dect_mac_connection_types - MAC Connection types + * + * @DECT_MAC_CONN_BASIC: Basic connection, always I_N_min_delay service + * @DECT_MAC_CONN_ADVANCED: Advanced connection + * @DECT_MAC_CONN_COMPLEMENT: Complementary connection + */ +enum dect_mac_connection_types { + DECT_MAC_CONN_BASIC, + DECT_MAC_CONN_ADVANCED, + DECT_MAC_CONN_COMPLEMENT, +}; + +enum dect_mac_service_types { + DECT_SERVICE_IN_MIN_DELAY = 0x0, + DECT_SERVICE_IPX_ENCODED_PROTECTED = 0x1, + DECT_SERVICE_IN_NORMAL_DELAY = 0x2, + DECT_SERVICE_UNKNOWN = 0x4, + DECT_SERVICE_C_CHANNEL_ONLY = 0x5, + DECT_SERVICE_IP_ERROR_DETECTION = 0x10, + DECT_SERVICE_IPQ_ERROR_DETECTION = 0x14, + /* Lifetime encoded in low three bits */ + DECT_SERVICE_IP_ERROR_CORRECTION = 0x18, + DECT_SERVICE_IPQ_ERROR_CORRECTION = 0x38, +}; + +/** + * enum dect_slot_types - DECT slot types + * + * @DECT_FULL_SLOT: Full-slot format (480 bits) + * @DECT_HALF_SLOT: Half-slot format (240 bits) + * @DECT_DOUBLE_SLOT: Double-slot format (960 bits) + * @DECT_LONG_SLOT_j640: Long slot format j=640 (800 bits) + * @DECT_LONG_SLOT_j672: Long slot format j=672 (832 bits) + * + * The numeric values must match the MAC-layer attributes-T coding. + */ +enum dect_slot_types { + DECT_FULL_SLOT = 0x0, + DECT_HALF_SLOT = 0x1, + DECT_DOUBLE_SLOT = 0x2, + DECT_LONG_SLOT_640 = 0x3, + DECT_LONG_SLOT_672 = 0x4, +}; + +struct dect_mac_conn_params { + enum dect_mac_connection_types type; + enum dect_mac_service_types service; + enum dect_slot_types slot; +}; + +/** + * struct dect_dl_encrypt - DL_ENCRYPT primitive arguments + * + * @status: desired/achieved encryption status + */ +struct dect_dl_encrypt { + enum dect_cipher_states status; +}; + +/** + * struct sockaddr_dect_lu - DLC U-plane LUx service instance address + * + * @dect_family: address family (AF_DECT) + * @dect_mci: MAC Connection Identifier + */ +struct sockaddr_dect_lu { + sa_family_t dect_family; + int dect_index; + __u64 dect_ari:40, + dect_pmid:20, + dect_lcn:3; +}; + +/* LU1 SAP */ + +#define DECT_LU1_QUEUE_STATS 0 + +struct dect_lu1_queue_stats { + __u32 rx_bytes; + __u32 rx_underflow; + __u32 tx_bytes; + __u32 tx_underflow; +}; + +#endif /* _LINUX_DECT_H */ diff --git a/include/linux/dect_netlink.h b/include/linux/dect_netlink.h new file mode 100644 index 0000000..7c01aca --- /dev/null +++ b/include/linux/dect_netlink.h @@ -0,0 +1,397 @@ +#ifndef _LINUX_DECT_NETLINK_H +#define _LINUX_DECT_NETLINK_H + +struct dectmsg { + int dm_index; +}; + +enum dect_nlgroups { + DECTNLGRP_NONE, + DECTNLGRP_TRANSCEIVER, + DECTNLGRP_CELL, + DECTNLGRP_CLUSTER, + DECTNLGRP_LLME, + __DECTNLGRP_MAX +}; +#define DECTNLGRP_MAX (__DECTNLGRP_MAX - 1) + +enum dect_netlink_msg_types { + DECT_MSG_BASE = 0x10, + DECT_NEW_TRANSCEIVER, + DECT_DEL_TRANSCEIVER, + DECT_GET_TRANSCEIVER, + DECT_NEW_CELL, + DECT_DEL_CELL, + DECT_GET_CELL, + DECT_NEW_CLUSTER, + DECT_DEL_CLUSTER, + DECT_GET_CLUSTER, + DECT_LLME_MSG, + __DECT_MSG_MAX +}; +#define DECT_MSG_MAX (__DECT_MSG_MAX - 1) + +#define DECT_NR_MSGTYPES (DECT_MSG_MAX + 1 - DECT_MSG_BASE) + +enum dect_list_attrs { + DECTA_LIST_UNSPEC, + DECTA_LIST_ELEM, + __DECTA_LIST_MAX +}; +#define DECTA_LIST_MAX (__DECTA_LIST_MAX - 1) + +enum dect_slot_states { + DECT_SLOT_IDLE, + DECT_SLOT_SCANNING, + DECT_SLOT_RX, + DECT_SLOT_TX, +}; + +enum dect_slot_flags { + DECT_SLOT_SYNC = 0x1, + DECT_SLOT_CIPHER = 0x2, +}; + +/** + * enum dect_packet_types - DECT Physical Packet Types + * + * @DECT_PACKET_P00: short physical packet P00, 96 bits, A-field only + * @DECT_PACKET_P08: low capacity physical packet P08j, 180 bits + * @DECT_PACKET_P32: basic physical packet P32, 420 bits + * @DECT_PACKET_P80: high capacity physical packet P80, 900 bits + * @DECT_PACKET_P640j: variable capacity packet P640j, 712 bits + * @DECT_PACKET_P672j: variable capacity packet P640j, 744 bits + */ +enum dect_packet_types { + DECT_PACKET_P00, + DECT_PACKET_P08, + DECT_PACKET_P32, + DECT_PACKET_P80, + DECT_PACKET_P640j, + DECT_PACKET_P672j, + __DECT_PACKET_MAX +}; +#define DECT_PACKET_MAX (__DECT_PACKET_MAX - 1) + +#define DECT_PHASE_OFFSET_SCALE 1024 + +enum dect_slot_attrs { + DECTA_SLOT_UNSPEC, + DECTA_SLOT_NUM, + DECTA_SLOT_STATE, + DECTA_SLOT_FLAGS, + DECTA_SLOT_PACKET, + DECTA_SLOT_CARRIER, + DECTA_SLOT_FREQUENCY, + DECTA_SLOT_PHASEOFF, + DECTA_SLOT_RSSI, + DECTA_SLOT_RX_PACKETS, + DECTA_SLOT_RX_BYTES, + DECTA_SLOT_RX_A_CRC_ERRORS, + DECTA_SLOT_RX_X_CRC_ERRORS, + DECTA_SLOT_RX_Z_CRC_ERRORS, + DECTA_SLOT_TX_PACKETS, + DECTA_SLOT_TX_BYTES, + __DECTA_SLOT_MAX +}; +#define DECTA_SLOT_MAX (__DECTA_SLOT_MAX - 1) + +enum dect_transceiver_stats_attrs { + DECTA_TRANSCEIVER_STATS_UNSPEC, + DECTA_TRANSCEIVER_STATS_EVENT_BUSY, + DECTA_TRANSCEIVER_STATS_EVENT_LATE, + __DECTA_TRANSCEIVER_STATS_MAX +}; +#define DECTA_TRANSCEIVER_STATS_MAX (__DECTA_TRANSCEIVER_STATS_MAX - 1) + +/** + * @DECT_TRANSCEIVER_SLOW_HOPPING: transceiver has slow hopping radio + * @DECT_TRANSCEIVER_PACKET_P64: transceiver supports packet P640j + */ +enum dect_transceiver_features { + DECT_TRANSCEIVER_SLOW_HOPPING = 0x1, + DECT_TRANSCEIVER_PACKET_P64 = 0x2, +}; + +enum dect_transceiver_attrs { + DECTA_TRANSCEIVER_UNSPEC, + DECTA_TRANSCEIVER_NAME, + DECTA_TRANSCEIVER_TYPE, + DECTA_TRANSCEIVER_FEATURES, + DECTA_TRANSCEIVER_LINK, + DECTA_TRANSCEIVER_STATS, + DECTA_TRANSCEIVER_BAND, + DECTA_TRANSCEIVER_SLOTS, + __DECTA_TRANSCEIVER_MAX +}; +#define DECTA_TRANSCEIVER_MAX (__DECTA_TRANSCEIVER_MAX - 1) + +enum dect_cell_flags { + DECT_CELL_CCP = (1 << 0), + DECT_CELL_SLAVE = (1 << 1), + DECT_CELL_MONITOR = (1 << 2), +}; + +enum dect_cell_attrs { + DECTA_CELL_UNSPEC, + DECTA_CELL_NAME, + DECTA_CELL_FLAGS, + DECTA_CELL_TRANSCEIVERS, + DECTA_CELL_CLUSTER, + __DECTA_CELL_MAX +}; +#define DECTA_CELL_MAX (__DECTA_CELL_MAX - 1) + +enum dect_mbc_state { + DECT_MBC_NONE, + DECT_MBC_INITIATED, + DECT_MBC_ESTABLISHED, + DECT_MBC_RELEASED, +}; + +enum dect_mbc_tb_attrs { + DECTA_MBC_TB_UNSPEC, + DECTA_MBC_TB_LBN, + DECTA_MBC_TB_ECN, + DECTA_MBC_TB_CELL, + DECTA_MBC_TB_RX_SLOT, + DECTA_MBC_TB_TX_SLOT, + __DECTA_MBC_TB_MAX, +}; +#define DECTA_MBC_TB_MAX (__DECTA_MBC_TB_MAX - 1) + +enum dect_mbc_stats_attrs { + DECTA_MBC_STATS_UNSPEC, + DECTA_MBC_STATS_CS_RX_BYTES, + DECTA_MBC_STATS_CS_TX_BYTES, + DECTA_MBC_STATS_I_RX_BYTES, + DECTA_MBC_STATS_I_TX_BYTES, + DECTA_MBC_STATS_HANDOVERS, + __DECTA_MBC_STATS_MAX, +}; +#define DECTA_MBC_STATS_MAX (__DECTA_MBC_STATS_MAX - 1) + +enum dect_mbc_attrs { + DECTA_MBC_UNSPEC, + DECTA_MBC_MCEI, + DECTA_MBC_SERVICE, + DECTA_MBC_STATE, + DECTA_MBC_CIPHER_STATE, + DECTA_MBC_STATS, + DECTA_MBC_TBS, + __DECTA_MBC_MAX, +}; +#define DECTA_MBC_MAX (__DECTA_MBC_MAX - 1) + +enum dect_cluster_attrs { + DECTA_CLUSTER_UNSPEC, + DECTA_CLUSTER_NAME, + DECTA_CLUSTER_MODE, + DECTA_CLUSTER_PARI, + DECTA_CLUSTER_CELLS, + DECTA_CLUSTER_MBCS, + __DECTA_CLUSTER_MAX +}; +#define DECTA_CLUSTER_MAX (__DECTA_CLUSTER_MAX - 1) + +enum dect_cluster_modes { + DECT_MODE_FP, + DECT_MODE_PP, +}; + +/** + * DECT ARI classes + * + * @DECT_ARC_A: Residential and private (PBX) single- and small multiple cell systems + * @DECT_ARC_B: Private (PABXs) multiple cell + * @DECT_ARC_C: Public single and multiple cell systems + * @DECT_ARC_D: Public DECT access to a GSM network + * @DECT_ARC_E: PP to PP direct communication (private) + */ +enum dect_ari_classes { + DECT_ARC_A, + DECT_ARC_B, + DECT_ARC_C, + DECT_ARC_D, + DECT_ARC_E, +}; + +enum dect_ari_attrs { + DECTA_ARI_UNSPEC, + DECTA_ARI_CLASS, + DECTA_ARI_FPN, + DECTA_ARI_FPS, + DECTA_ARI_EMC, + DECTA_ARI_EIC, + DECTA_ARI_POC, + DECTA_ARI_GOP, + DECTA_ARI_FIL, + __DECTA_ARI_MAX +}; +#define DECTA_ARI_MAX (__DECTA_ARI_MAX - 1) + +enum decta_sari_attrs { + DECTA_SARI_UNSPEC, + DECTA_SARI_ARI, + DECTA_SARI_BLACK, + DECTA_SARI_TARI, + __DECTA_SARI_MAX +}; +#define DECTA_SARI_MAX (__DECTA_SARI_MAX - 1) + +enum dect_fixed_part_capabilities { + DECT_FPC_EXTENDED_FP_INFO = 0x80000, + DECT_FPC_DOUBLE_DUPLEX_BEARER_CONNECTION= 0x40000, + DECT_FPC_RESERVED = 0x20000, + DECT_FPC_DOUBLE_SLOT = 0x10000, + DECT_FPC_HALF_SLOT = 0x08000, + DECT_FPC_FULL_SLOT = 0x04000, + DECT_FPC_FREQ_CONTROL = 0x02000, + DECT_FPC_PAGE_REPETITION = 0x01000, + DECT_FPC_CO_SETUP_ON_DUMMY = 0x00800, + DECT_FPC_CL_UPLINK = 0x00400, + DECT_FPC_CL_DOWNLINK = 0x00200, + DECT_FPC_BASIC_A_FIELD_SETUP = 0x00100, + DECT_FPC_ADV_A_FIELD_SETUP = 0x00080, + DECT_FPC_B_FIELD_SETUP = 0x00040, + DECT_FPC_CF_MESSAGES = 0x00020, + DECT_FPC_IN_MIN_DELAY = 0x00010, + DECT_FPC_IN_NORM_DELAY = 0x00008, + DECT_FPC_IP_ERROR_DETECTION = 0x00004, + DECT_FPC_IP_ERROR_CORRECTION = 0x00002, + DECT_FPC_MULTIBEARER_CONNECTIONS = 0x00001, +}; + +enum dect_higher_layer_capabilities { + DECT_HLC_ADPCM_G721_VOICE = 0x8000, + DECT_HLC_GAP_PAP_BASIC_SPEECH = 0x4000, + DECT_HLC_NON_VOICE_CIRCUIT_SWITCHED = 0x2000, + DECT_HLC_NON_VOICE_PACKET_SWITCHED = 0x1000, + DECT_HLC_STANDARD_AUTHENTICATION = 0x0800, + DECT_HLC_STANDARD_CIPHERING = 0x0400, + DECT_HLC_LOCATION_REGISTRATION = 0x0200, + DECT_HLC_SIM_SERVICES = 0x0100, + DECT_HLC_NON_STATIC_FIXED_PART = 0x0080, + DECT_HLC_CISS_SERVICE = 0x0040, + DECT_HLC_CLMS_SERVICE = 0x0020, + DECT_HLC_COMS_SERVICE = 0x0010, + DECT_HLC_ACCESS_RIGHTS_REQUESTS = 0x0008, + DECT_HLC_EXTERNAL_HANDOVER = 0x0004, + DECT_HLC_CONNECTION_HANDOVER = 0x0002, + DECT_HLC_RESERVED = 0x0001, +}; + +enum dect_extended_fixed_part_capabilities { + DECT_EFPC_WRS_MASK = 0x1f80, + DECT_EFPC_WRS_CRFP_HOPS_MASK = 0x1800, + DECT_EFPC_WRS_CRFP_HOPS_1 = 0x0000, + DECT_EFPC_WRS_CRFP_HOPS_2 = 0x0800, + DECT_EFPC_WRS_CRFP_HOPS_3 = 0x1000, + DECT_EFPC_WRS_CRFP_HOPS_NONE = 0x1800, + DECT_EFPC_WRS_CRFP_ENCRYPTION = 0x0400, + DECT_EFPC_WRS_REP_HOPS_MASK = 0x0300, + DECT_EFPC_WRS_REP_HOPS_NONE = 0x0000, + DECT_EFPC_WRS_REP_HOPS_1 = 0x0100, + DECT_EFPC_WRS_REP_HOPS_2 = 0x0200, + DECT_EFPC_WRS_REP_HOPS_3 = 0x0300, + DECT_EFPC_WRS_REP_INTERLACING = 0x0080, + DECT_EFPC_SYNC_MASK = 0x0060, + DECT_EFPC_SYNC_PROLONGED_PREAMBLE = 0x0020, + DECT_EFPC_SYNC_RESERVED1 = 0x0010, + DECT_EFPC_MAC_SUSPEND_RESUME = 0x0008, + DECT_EFPC_MAC_IP_Q_SERVICE = 0x0004, + DECT_EFPC_EXTENDED_FP_INFO2 = 0x0002, + DECT_EFPC_RESERVED2 = 0x0001, +}; + +enum dect_extended_higher_layer_capabilities { + DECT_EHLC_ISDN_DATA_SERVICE = 0x000001, + DECT_EHLC_DPRS_FREL = 0x000002, + DECT_EHLC_DPRS_STREAM = 0x000004, + DECT_EHLC_DATA_SERVICE_PROFILE_D = 0x000008, + DECT_EHLC_LRMS = 0x000010, + DECT_EHLC_ASYMETRIC_BEARERS = 0x000040, + DECT_EHLC_EMERGENCY_CALLS = 0x000080, + DECT_EHLC_TPUI_LOCATION_REGISTRATION = 0x000100, + DECT_EHLC_GPS_SYNCHRONIZED = 0x000200, + DECT_EHLC_ISDN_INTERMEDIATE_SYSTEM = 0x000400, + DECT_EHLC_RAP_PART_1_PROFILE = 0x000800, + DECT_EHLC_V_24 = 0x004000, + DECT_EHLC_PPP = 0x008000, + DECT_EHLC_IP = 0x010000, + DECT_EHLC_TOKEN_RING = 0x020000, + DECT_EHLC_ETHERNET = 0x040000, + DECT_EHLC_IP_ROAMING = 0x080000, + DECT_EHLC_GENERIC_MEDIA_ENCAPSULATION = 0x100000, + DECT_EHLC_BASIC_ODAP = 0x200000, + DECT_EHLC_F_MMS_INTERWORKING_PROFILE = 0x400000, +}; + +enum dect_extended_fixed_part_capabilities2 { + DECT_EFPC2_LONG_SLOT_J640 = 0x800, + DECT_EFPC2_LONG_SLOT_J672 = 0x400, + DECT_EFPC2_IP_F = 0x200, + DECT_EFPC2_SI_PF = 0x100, + DECT_EFPC2_GF = 0x080, + DECT_EFPC2_NO_EMISSION_CARRIER = 0x001, +}; + +enum dect_extended_higher_layer_capabilities2 { + DECT_EHLC2_NG_DECT_PERMANENT_CLIR = 0x000100, + DECT_EHLC2_NG_DECT_MULTIPLE_CALLS = 0x000200, + DECT_EHLC2_NG_DECT_MULTIPLE_LINES = 0x000400, + DECT_EHLC2_EASY_PAIRING = 0x000800, + DECT_EHLC2_LIST_ACCESS_FEATURES = 0x001000, + DECT_EHLC2_NO_EMISSION_MODE = 0x002000, + DECT_EHLC2_NG_DECT_CALL_DEFLECTION = 0x004000, + DECT_EHLC2_NG_DECT_INTRUSION_CALL = 0x008000, + DECT_EHLC2_NG_DECT_CONFERENCE_CALL = 0x010000, + DECT_EHLC2_NG_DECT_PARALLEL_CALLS = 0x020000, + DECT_EHLC2_NG_DECT_CALL_TRANSFER = 0x040000, + DECT_EHLC2_NG_DECT_EXTENDED_WIDEBAND = 0x080000, + DECT_EHLC2_PACKET_DATA_CATEGORY_MASK = 0x700000, + DECT_EHLC2_NG_DECT_WIDEBAND = 0x800000, +}; + +enum dect_mac_info_attrs { + DECTA_MAC_INFO_UNSPEC, + DECTA_MAC_INFO_PARI, + DECTA_MAC_INFO_RPN, + DECTA_MAC_INFO_RSSI, + DECTA_MAC_INFO_SARI_LIST, + DECTA_MAC_INFO_FPC, + DECTA_MAC_INFO_HLC, + DECTA_MAC_INFO_EFPC, + DECTA_MAC_INFO_EHLC, + DECTA_MAC_INFO_EFPC2, + DECTA_MAC_INFO_EHLC2, + DECTA_MAC_INFO_MFN, + __DECTA_MAC_INFO_MAX +}; +#define DECTA_MAC_INFO_MAX (__DECTA_MAC_INFO_MAX - 1) + +enum dect_llme_ops { + DECT_LLME_REQUEST, + DECT_LLME_INDICATE, + DECT_LLME_RESPONSE, + DECT_LLME_CONFIRM, +}; + +enum dect_llme_msg_types { + DECT_LLME_SCAN, + DECT_LLME_MAC_INFO, + DECT_LLME_MAC_RFP_PRELOAD, + __DECT_LLME_MAX +}; +#define DECT_LLME_MAX (__DECT_LLME_MAX - 1) + +enum dect_llme_msg_attrs { + DECTA_LLME_UNSPEC, + DECTA_LLME_OP, + DECTA_LLME_TYPE, + DECTA_LLME_DATA, + __DECTA_LLME_MAX +}; +#define DECTA_LLME_MAX (__DECTA_LLME_MAX - 1) + +#endif /* _LINUX_DECT_NETLINK_H */ diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 3925254..d427fcc 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -25,6 +25,8 @@ #define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */ #define NETLINK_ECRYPTFS 19 #define NETLINK_RDMA 20 +#define NETLINK_CRYPTO 21 /* Crypto layer */ +#define NETLINK_DECT 22 /* DECT */ #define MAX_LINKS 32 diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h index 89f6418..6e2fa68 100644 --- a/include/netlink-private/types.h +++ b/include/netlink-private/types.h @@ -903,6 +903,140 @@ struct nfnl_queue_msg { uint32_t queue_msg_verdict; }; +struct nl_dect_transceiver_slot { + uint8_t dts_valid; + uint8_t dts_state; + uint32_t dts_flags; + uint8_t dts_packet; + uint8_t dts_carrier; + uint8_t dts_rssi; + uint32_t dts_frequency; + int32_t dts_phaseoff; + uint32_t dts_rx_bytes; + uint32_t dts_rx_packets; + uint32_t dts_rx_a_crc_errors; + uint32_t dts_rx_x_crc_errors; + uint32_t dts_rx_z_crc_errors; + uint32_t dts_tx_bytes; + uint32_t dts_tx_packets; +}; + +struct nl_dect_transceiver_stats { + uint32_t trx_event_busy; + uint32_t trx_event_late; +}; + +struct nl_dect_transceiver { + NLHDR_COMMON + + char *trx_name; + char *trx_type; + uint32_t trx_features; + uint8_t trx_index; + uint8_t trx_link; + uint8_t trx_band; + struct nl_dect_transceiver_stats trx_stats; + struct nl_dect_transceiver_slot trx_slots[24]; +}; + +struct nl_dect_ari { + uint32_t ari_flags; + + uint8_t ari_class; + uint32_t ari_fpn; + uint32_t ari_fps; + union { + uint16_t emc; + uint16_t eic; + uint16_t poc; + uint32_t gop; + uint16_t fil; + } ari_u; +}; + +struct nl_dect_mbc_tb { + uint8_t mtb_lbn; + uint8_t mtb_ecn; + uint8_t mtb_cell; + uint8_t mtb_rx_slot; + uint8_t mtb_tx_slot; +}; + +struct nl_dect_mbc { + uint32_t mbc_mcei; + uint8_t mbc_state; + uint8_t mbc_service; + uint8_t mbc_cipher_state; + uint8_t mbc_ntbs; + struct nl_dect_mbc_tb mbc_tbs[8]; + + uint32_t mbc_cs_rx_bytes; + uint32_t mbc_cs_tx_bytes; + uint32_t mbc_i_rx_bytes; + uint32_t mbc_i_tx_bytes; + uint32_t mbc_handovers; +}; + +struct nl_dect_cluster { + NLHDR_COMMON + + int cl_index; + char *cl_name; + uint8_t cl_mode; + struct nl_dect_ari cl_pari; + uint8_t cells[8]; + struct nl_dect_mbc cl_mbcs[8]; + uint8_t cl_nmbcs; +}; + +struct nl_dect_cell { + NLHDR_COMMON + + int c_index; + char * c_name; + uint32_t c_flags; + char *c_transceiver[16]; + int c_link; +}; + +struct nl_dect_llme_mac_info { + NLHDR_COMMON + + struct nl_dect_ari mi_pari; + uint8_t mi_rpn; + uint8_t mi_rssi; + uint32_t mi_fpc; + uint16_t mi_hlc; + uint16_t mi_efpc; + uint32_t mi_ehlc; + uint16_t mi_efpc2; + uint32_t mi_ehlc2; + uint32_t mi_mfn; +}; + +struct nl_dect_llme_mac_con { + NLHDR_COMMON + + uint32_t mc_mcei; + struct nl_dect_ari mc_ari; + uint32_t mc_pmid; + uint8_t mc_type; + uint8_t mc_ecn; + uint8_t mc_service; +}; + +struct nl_dect_llme_msg { + NLHDR_COMMON + + int lm_index; + uint8_t lm_type; + uint8_t lm_op; + union { + struct nl_dect_llme_mac_info lm_mi; + struct nl_dect_llme_mac_con lm_mc; + }; +}; + struct ematch_quoted { char * data; size_t len; diff --git a/include/netlink/cli/utils.h b/include/netlink/cli/utils.h index da41c10..cd0df83 100644 --- a/include/netlink/cli/utils.h +++ b/include/netlink/cli/utils.h @@ -22,6 +22,7 @@ #include <stdint.h> #include <ctype.h> #include <getopt.h> +#include <limits.h> #include <dlfcn.h> #include <sys/types.h> #include <sys/socket.h> @@ -47,6 +48,11 @@ #include <netlink/genl/ctrl.h> #include <netlink/genl/mngt.h> #include <netlink/netfilter/ct.h> +#include <netlink/dect/transceiver.h> +#include <netlink/dect/cell.h> +#include <netlink/dect/cluster.h> +#include <netlink/dect/llme.h> +#include <netlink/dect/ari.h> #ifdef __cplusplus extern "C" { diff --git a/include/netlink/dect/ari.h b/include/netlink/dect/ari.h new file mode 100644 index 0000000..76c7813 --- /dev/null +++ b/include/netlink/dect/ari.h @@ -0,0 +1,39 @@ +#ifndef NETLINK_DECT_ARI_H +#define NETLINK_DECT_ARI_H + +#include <stdbool.h> + +struct nl_dect_ari; + +extern int nl_dect_parse_ari(struct nl_dect_ari *, + struct nlattr *); +extern int nl_dect_fill_ari(struct nl_msg *, + const struct nl_dect_ari *, + int); +extern void nl_dect_dump_ari(const struct nl_dect_ari *, + struct nl_dump_params *); + +extern const char * nl_dect_ari_class2str(enum dect_ari_classes, + char *buf, size_t len); +extern enum dect_ari_classes nl_dect_ari_str2class(const char *); + +extern void nl_dect_ari_set_class(struct nl_dect_ari *, + enum dect_ari_classes); +extern enum dect_ari_classes nl_dect_ari_get_class(const struct nl_dect_ari *); + +extern void nl_dect_ari_set_fpn(struct nl_dect_ari *, uint32_t); +extern uint32_t nl_dect_ari_get_fpn(const struct nl_dect_ari *); +extern void nl_dect_ari_set_fps(struct nl_dect_ari *, uint32_t); +extern uint32_t nl_dect_ari_get_fps(const struct nl_dect_ari *); +extern void nl_dect_ari_set_emc(struct nl_dect_ari *, uint16_t); +extern uint16_t nl_dect_ari_get_emc(const struct nl_dect_ari *); +extern void nl_dect_ari_set_eic(struct nl_dect_ari *, uint16_t); +extern uint16_t nl_dect_ari_get_eic(const struct nl_dect_ari *); +extern void nl_dect_ari_set_poc(struct nl_dect_ari *, uint16_t); +extern uint16_t nl_dect_ari_get_poc(const struct nl_dect_ari *); +extern void nl_dect_ari_set_gop(struct nl_dect_ari *, uint32_t); +extern uint32_t nl_dect_ari_get_gop(const struct nl_dect_ari *); +extern void nl_dect_ari_set_fil(struct nl_dect_ari *, uint16_t); +extern uint16_t nl_dect_ari_get_fil(const struct nl_dect_ari *); + +#endif /* NETLINK_DECT_ARI_H */ diff --git a/include/netlink/dect/cell.h b/include/netlink/dect/cell.h new file mode 100644 index 0000000..e1b0f30 --- /dev/null +++ b/include/netlink/dect/cell.h @@ -0,0 +1,61 @@ +#ifndef NETLINK_DECT_CELL_H +#define NETLINK_DECT_CELL_H + +#include <stdbool.h> + +struct nl_dect_cell; +struct nl_dect_ari; + +extern struct nl_object_ops nl_dect_cell_obj_ops; + +extern struct nl_dect_cell * nl_dect_cell_alloc(void); +extern void nl_dect_cell_get(struct nl_dect_cell *); +extern void nl_dect_cell_put(struct nl_dect_cell *); + +extern void nl_dect_cell_set_index(struct nl_dect_cell *, int); +extern bool nl_dect_cell_test_index(const struct nl_dect_cell *); +extern int nl_dect_cell_get_index(const struct nl_dect_cell *); + +extern void nl_dect_cell_set_name(struct nl_dect_cell *, const char *); +extern bool nl_dect_cell_test_name(const struct nl_dect_cell *); +extern const char * nl_dect_cell_get_name(const struct nl_dect_cell *); + +extern void nl_dect_cell_set_flags(struct nl_dect_cell *, uint32_t); +extern bool nl_dect_cell_test_flags(const struct nl_dect_cell *); +extern uint32_t nl_dect_cell_get_flags(const struct nl_dect_cell *); + +extern void nl_dect_cell_set_transceiver(struct nl_dect_cell *, + unsigned int, + const char *); +extern bool nl_dect_cell_test_transceiver(const struct nl_dect_cell *); +extern const char * nl_dect_cell_get_transceiver(const struct nl_dect_cell *, + unsigned int); + +extern void nl_dect_cell_set_link(struct nl_dect_cell *, int); +extern bool nl_dect_cell_test_link(const struct nl_dect_cell *); +extern int nl_dect_cell_get_link(const struct nl_dect_cell *); + +extern int nl_dect_cell_alloc_cache(struct nl_sock *, + struct nl_cache **); + +extern int nl_dect_cell_build_msg(struct nl_msg *, + struct nl_dect_cell *); + +extern int nl_dect_cell_build_add_request(struct nl_dect_cell *, + int, struct nl_msg **); +extern int nl_dect_cell_add(struct nl_sock *, + struct nl_dect_cell *, int); + +extern int nl_dect_cell_build_del_request(struct nl_dect_cell *, + int, struct nl_msg **); +extern int nl_dect_cell_delete(struct nl_sock *, + struct nl_dect_cell *, int); + +extern char * nl_dect_cell_i2name(struct nl_cache *, int, char *, + size_t); +extern int nl_dect_cell_name2i(struct nl_cache *, const char *); + +extern char * nl_dect_cell_flags2str(uint32_t, char *, size_t); +extern uint32_t nl_dect_cell_str2flags(const char *); + +#endif /* NETLINK_DECT_CELL_H */ diff --git a/include/netlink/dect/cluster.h b/include/netlink/dect/cluster.h new file mode 100644 index 0000000..43f79e1 --- /dev/null +++ b/include/netlink/dect/cluster.h @@ -0,0 +1,61 @@ +#ifndef NETLINK_DECT_CLUSTER_H +#define NETLINK_DECT_CLUSTER_H + +#include <stdbool.h> + +struct nl_dect_cluster; +struct nl_dect_ari; + +extern struct nl_object_ops nl_dect_cluster_obj_ops; + +extern struct nl_dect_cluster * nl_dect_cluster_alloc(void); +extern void nl_dect_cluster_get(struct nl_dect_cluster *); +extern void nl_dect_cluster_put(struct nl_dect_cluster *); + +extern unsigned int nl_dect_cluster_get_index(const struct nl_dect_cluster *); + +extern void nl_dect_cluster_set_name(struct nl_dect_cluster *, + const char *); +extern bool nl_dect_cluster_test_name(const struct nl_dect_cluster *); +extern const char * nl_dect_cluster_get_name(const struct nl_dect_cluster *); + +extern void nl_dect_cluster_set_mode(struct nl_dect_cluster *, + uint8_t mode); +extern bool nl_dect_cluster_test_mode(const struct nl_dect_cluster *); +extern uint8_t nl_dect_cluster_get_mode(const struct nl_dect_cluster *); + +extern void nl_dect_cluster_set_pari(struct nl_dect_cluster *, + const struct nl_dect_ari *); +extern bool nl_dect_cluster_test_pari(const struct nl_dect_cluster *); +extern const struct nl_dect_ari *nl_dect_cluster_get_pari(const struct nl_dect_cluster *); + +extern char * nl_dect_cluster_mode2str(enum dect_cluster_modes, + char *, size_t); +extern enum dect_cluster_modes nl_dect_cluster_str2mode(const char *); + +extern int nl_dect_cluster_alloc_cache(struct nl_sock *, + struct nl_cache **); + +extern int nl_dect_cluster_build_msg(struct nl_msg *, + struct nl_dect_cluster *); + +extern int nl_dect_cluster_build_add_request(struct nl_dect_cluster *, + int, struct nl_msg **); +extern int nl_dect_cluster_add(struct nl_sock *, + struct nl_dect_cluster *, int); + +extern int nl_dect_cluster_build_del_request(struct nl_dect_cluster *, + int, struct nl_msg **); +extern int nl_dect_cluster_delete(struct nl_sock *, + struct nl_dect_cluster *, int); + +extern int nl_dect_cluster_build_query_request(struct nl_dect_cluster *, + int, struct nl_msg **); +extern int nl_dect_cluster_query(struct nl_sock *, + struct nl_dect_cluster *, int); + +extern char * nl_dect_cluster_i2name(struct nl_cache *, int, char *, + size_t); +extern int nl_dect_cluster_name2i(struct nl_cache *, const char *); + +#endif /* NETLINK_DECT_CLUSTER_H */ diff --git a/include/netlink/dect/dect.h b/include/netlink/dect/dect.h new file mode 100644 index 0000000..2a28864 --- /dev/null +++ b/include/netlink/dect/dect.h @@ -0,0 +1,6 @@ +#ifndef _NETLINK_DECT_H +#define _NETLINK_DECT_H + +extern double nl_dect_rssi_to_dbm(uint8_t); + +#endif /* _NETLINK_DECT_H */ diff --git a/include/netlink/dect/llme.h b/include/netlink/dect/llme.h new file mode 100644 index 0000000..85cf9cc --- /dev/null +++ b/include/netlink/dect/llme.h @@ -0,0 +1,94 @@ +#ifndef NETLINK_DECT_LLME_H +#define NETLINK_DECT_LLME_H + +#include <stdbool.h> + +struct nl_dect_llme_msg; +struct nl_dect_ari; + +extern struct nl_dect_llme_msg *nl_dect_llme_msg_alloc(void); +extern void nl_dect_llme_msg_get(struct nl_dect_llme_msg *); +extern void nl_dect_llme_msg_put(struct nl_dect_llme_msg *); + +extern int nl_dect_llme_build_request(struct nl_dect_llme_msg *, + struct nl_msg **); +extern int nl_dect_llme_request(struct nl_sock *, + struct nl_dect_llme_msg *); + +extern int nl_dect_llme_build_response(struct nl_dect_llme_msg *, + struct nl_msg **); +extern int nl_dect_llme_respond(struct nl_sock *, struct nl_dect_llme_msg *); + +extern void nl_dect_llme_msg_set_index(struct nl_dect_llme_msg *, int); +extern void nl_dect_llme_msg_set_type(struct nl_dect_llme_msg *, + enum dect_llme_msg_types); +extern enum dect_llme_msg_types nl_dect_llme_msg_get_type(const struct nl_dect_llme_msg *); +extern void nl_dect_llme_msg_set_op(struct nl_dect_llme_msg *, + enum dect_llme_ops); +extern enum dect_llme_ops nl_dect_llme_msg_get_op(const struct nl_dect_llme_msg *); + +extern char * nl_dect_llme_msgtype2str(enum dect_llme_msg_types, + char *, size_t); +extern enum dect_llme_msg_types nl_dect_llme_str2msgtype(const char *); + +extern char * nl_dect_llme_op2str(enum dect_llme_ops, + char *, size_t); +extern enum dect_llme_ops nl_dect_llme_str2op(const char *); + + +extern void nl_dect_llme_mac_info_set_pari(struct nl_dect_llme_msg *lmsg, + const struct nl_dect_ari *); +extern bool nl_dect_llme_mac_info_test_pari(const struct nl_dect_llme_msg *); +extern const struct nl_dect_ari *nl_dect_llme_mac_info_get_pari(const struct nl_dect_llme_msg *); + +extern void nl_dect_llme_mac_info_set_rpn(struct nl_dect_llme_msg *, + uint8_t); +extern uint8_t nl_dect_llme_mac_info_get_rpn(const struct nl_dect_llme_msg *); + +extern void nl_dect_llme_mac_info_set_rssi(struct nl_dect_llme_msg *, + uint8_t); +extern uint8_t nl_dect_llme_mac_info_get_rssi(const struct nl_dect_llme_msg *); + +extern void nl_dect_llme_mac_info_set_fpc(struct nl_dect_llme_msg *, + uint32_t); +extern uint32_t nl_dect_llme_mac_info_get_fpc(const struct nl_dect_llme_msg *); + +extern void nl_dect_llme_mac_info_set_hlc(struct nl_dect_llme_msg *, + uint16_t); +extern uint16_t nl_dect_llme_mac_info_get_hlc(const struct nl_dect_llme_msg *); + +extern void nl_dect_llme_mac_info_set_efpc(struct nl_dect_llme_msg *, + uint16_t); +extern uint16_t nl_dect_llme_mac_info_get_efpc(const struct nl_dect_llme_msg *); + +extern void nl_dect_llme_mac_info_set_ehlc(struct nl_dect_llme_msg *, + uint32_t); +extern uint32_t nl_dect_llme_mac_info_get_ehlc(const struct nl_dect_llme_msg *); + +extern void nl_dect_llme_mac_info_set_efpc2(struct nl_dect_llme_msg *, + uint16_t); +extern uint16_t nl_dect_llme_mac_info_get_efpc2(const struct nl_dect_llme_msg *); + +extern void nl_dect_llme_mac_info_set_ehlc2(struct nl_dect_llme_msg *, + uint32_t); +extern uint32_t nl_dect_llme_mac_info_get_ehlc2(const struct nl_dect_llme_msg *); + +extern char * nl_dect_llme_fpc2str(uint32_t, char *, size_t); +extern uint32_t nl_dect_llme_str2fpc(const char *); + +extern char * nl_dect_llme_hlc2str(uint16_t, char *, size_t); +extern uint16_t nl_dect_llme_str2hlc(const char *); + +extern char * nl_dect_llme_efpc2str(uint16_t, char *, size_t); +extern uint16_t nl_dect_llme_str2efpc(const char *); + +extern char * nl_dect_llme_ehlc2str(uint32_t, char *, size_t); +extern uint32_t nl_dect_llme_str2ehlc(const char *); + +extern char * nl_dect_llme_efpc22str(uint16_t, char *, size_t); +extern uint16_t nl_dect_llme_str22efpc(const char *); + +extern char * nl_dect_llme_ehlc22str(uint32_t, char *, size_t); +extern uint32_t nl_dect_llme_str22ehlc(const char *); + +#endif /* NETLINK_DECT_LLME_H */ diff --git a/include/netlink/dect/transceiver.h b/include/netlink/dect/transceiver.h new file mode 100644 index 0000000..28dff52 --- /dev/null +++ b/include/netlink/dect/transceiver.h @@ -0,0 +1,57 @@ +#ifndef NETLINK_DECT_TRANSCEIVER_H +#define NETLINK_DECT_TRANSCEIVER_H + +#include <stdbool.h> + +struct nl_dect_transceiver; + +extern struct nl_object_ops nl_dect_transceiver_obj_ops; + +extern struct nl_dect_transceiver *nl_dect_transceiver_alloc(void); +extern void nl_dect_transceiver_get(struct nl_dect_transceiver *); +extern void nl_dect_transceiver_put(struct nl_dect_transceiver *); + +extern void nl_dect_transceiver_set_name(struct nl_dect_transceiver *, + const char *); +extern bool nl_dect_transceiver_test_name(const struct nl_dect_transceiver *); +extern const char * nl_dect_transceiver_get_name(const struct nl_dect_transceiver *); + +extern void nl_dect_transceiver_set_type(struct nl_dect_transceiver *, + const char *); +extern bool nl_dect_transceiver_test_type(const struct nl_dect_transceiver *); +extern const char * nl_dect_transceiver_get_type(const struct nl_dect_transceiver *); + +extern void nl_dect_transceiver_set_features(struct nl_dect_transceiver *, + uint32_t); +extern void nl_dect_transceiver_set_index(struct nl_dect_transceiver *, + int); +extern void nl_dect_transceiver_set_link(struct nl_dect_transceiver *, + uint8_t); + +extern void nl_dect_transceiver_set_band(struct nl_dect_transceiver *, + uint8_t); +extern bool nl_dect_transceiver_test_band(const struct nl_dect_transceiver *); +extern uint8_t nl_dect_transceiver_get_band(const struct nl_dect_transceiver *); + +extern int nl_dect_transceiver_build_msg(struct nl_msg *, + struct nl_dect_transceiver *); +extern int nl_dect_transceiver_build_change_request(struct nl_dect_transceiver *, + int, struct nl_msg **); +extern int nl_dect_transceiver_change(struct nl_sock *, + struct nl_dect_transceiver *, int flags); + +extern const char * nl_dect_transceiver_features2str(uint32_t, char *, size_t); + +extern const char * nl_dect_slot_state2str(uint8_t, char *, size_t); +extern uint8_t nl_dect_slot_str2state(const char *); + +extern const char * nl_dect_slot_flags2str(uint32_t, char *, size_t); +extern uint32_t nl_dect_slot_str2flags(const char *); + +extern const char * nl_dect_slot_packet2str(uint8_t, char *, size_t); +extern uint8_t nl_dect_slot_str2packet(const char *); + +extern int nl_dect_transceiver_alloc_cache(struct nl_sock *, + struct nl_cache **); + +#endif /* NETLINK_DECT_TRANSCEIVER_H */ diff --git a/include/netlink/netlink.h b/include/netlink/netlink.h index 1d74ba1..c65c303 100644 --- a/include/netlink/netlink.h +++ b/include/netlink/netlink.h @@ -26,6 +26,7 @@ #include <linux/rtnetlink.h> #include <linux/genetlink.h> #include <linux/netfilter/nfnetlink.h> +#include <linux/dect_netlink.h> #include <netlink/version.h> #include <netlink/errno.h> #include <netlink/types.h> diff --git a/lib/Makefile.am b/lib/Makefile.am index 677a89c..438b3eb 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -13,7 +13,7 @@ AM_LDFLAGS = \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) lib_LTLIBRARIES = \ - libnl-3.la libnl-genl-3.la libnl-route-3.la libnl-nf-3.la + libnl-3.la libnl-genl-3.la libnl-route-3.la libnl-nf-3.la libnl-dect-3.la libnl_3_la_SOURCES = \ addr.c attr.c cache.c cache_mngr.c cache_mngt.c data.c \ @@ -32,6 +32,12 @@ libnl_nf_3_la_SOURCES = \ netfilter/queue_msg.c netfilter/queue_msg_obj.c netfilter/queue_obj.c \ netfilter/exp.c netfilter/exp_obj.c +libnl_dect_3_la_LIBADD = libnl-3.la +libnl_dect_3_la_SOURCES = \ + dect/ari.c dect/cell.c dect/cell_obj.c \ + dect/cluster.c dect/cluster_obj.c dect/dect.c dect/llme.c \ + dect/transceiver.c dect/transceiver_obj.c + CLEANFILES = \ route/pktloc_grammar.c route/pktloc_grammar.h \ route/pktloc_syntax.c route/pktloc_syntax.h \ diff --git a/lib/dect/ari.c b/lib/dect/ari.c new file mode 100644 index 0000000..d17d4f8 --- /dev/null +++ b/lib/dect/ari.c @@ -0,0 +1,245 @@ +#include <netlink-private/netlink.h> +#include <netlink/netlink.h> +#include <netlink/utils.h> +#include <netlink/dect/ari.h> +#include <linux/dect_netlink.h> + +#define ARI_ATTR_CLASS 0x01 +#define ARI_ATTR_FPN 0x02 +#define ARI_ATTR_FPS 0x03 +#define ARI_ATTR_EMC 0x04 +#define ARI_ATTR_EIC 0x05 +#define ARI_ATTR_POC 0x06 +#define ARI_ATTR_GOP 0x07 +#define ARI_ATTR_FIL 0x08 + +static struct nla_policy nl_dect_ari_policy[DECTA_ARI_MAX + 1] = { + [DECTA_ARI_CLASS] = { .type = NLA_U8 }, + [DECTA_ARI_FPN] = { .type = NLA_U32 }, + [DECTA_ARI_FPS] = { .type = NLA_U32 }, + [DECTA_ARI_EMC] = { .type = NLA_U16 }, + [DECTA_ARI_EIC] = { .type = NLA_U16 }, + [DECTA_ARI_POC] = { .type = NLA_U16 }, + [DECTA_ARI_GOP] = { .type = NLA_U32 }, + [DECTA_ARI_FIL] = { .type = NLA_U32 }, +}; + +int nl_dect_parse_ari(struct nl_dect_ari *ari, struct nlattr *nla) +{ + struct nlattr *tb[DECTA_ARI_MAX + 1]; + int err; + + err = nla_parse_nested(tb, DECTA_ARI_MAX, nla, nl_dect_ari_policy); + if (err < 0) + return err; + + if (tb[DECTA_ARI_CLASS] == NULL) + return -NLE_INVAL; + + memset(ari, 0, sizeof(ari)); + ari->ari_class = nla_get_u8(tb[DECTA_ARI_CLASS]); + if (tb[DECTA_ARI_FPN] != NULL) + ari->ari_fpn = nla_get_u32(tb[DECTA_ARI_FPN]); + + switch (ari->ari_class) { + case DECT_ARC_A: + if (tb[DECTA_ARI_EMC] != NULL) + ari->ari_u.emc = nla_get_u16(tb[DECTA_ARI_EMC]); + break; + case DECT_ARC_B: + if (tb[DECTA_ARI_EIC] != NULL) + ari->ari_u.eic = nla_get_u16(tb[DECTA_ARI_EIC]); + if (tb[DECTA_ARI_FPS] != NULL) + ari->ari_fps = nla_get_u32(tb[DECTA_ARI_FPS]); + break; + case DECT_ARC_C: + if (tb[DECTA_ARI_POC] != NULL) + ari->ari_u.poc = nla_get_u16(tb[DECTA_ARI_POC]); + if (tb[DECTA_ARI_FPS] != NULL) + ari->ari_fps = nla_get_u32(tb[DECTA_ARI_FPS]); + break; + case DECT_ARC_D: + if (tb[DECTA_ARI_GOP] != NULL) + ari->ari_u.gop = nla_get_u32(tb[DECTA_ARI_GOP]); + break; + case DECT_ARC_E: + if (tb[DECTA_ARI_FIL] != NULL) + ari->ari_u.fil = nla_get_u16(tb[DECTA_ARI_FIL]); + break; + default: + return -NLE_INVAL; + } + + return 0; +} + +int nl_dect_fill_ari(struct nl_msg *msg, const struct nl_dect_ari *ari, int attr) +{ + struct nlattr *nla; + + nla = nla_nest_start(msg, attr); + if (nla == NULL) + goto nla_put_failure; + + NLA_PUT_U8(msg, DECTA_ARI_CLASS, ari->ari_class); + NLA_PUT_U32(msg, DECTA_ARI_FPN, ari->ari_fpn); + + switch (ari->ari_class) { + case DECT_ARC_A: + NLA_PUT_U16(msg, DECTA_ARI_EMC, ari->ari_u.emc); + break; + case DECT_ARC_B: + NLA_PUT_U16(msg, DECTA_ARI_EIC, ari->ari_u.eic); + NLA_PUT_U32(msg, DECTA_ARI_FPS, ari->ari_fps); + break; + case DECT_ARC_C: + NLA_PUT_U16(msg, DECTA_ARI_POC, ari->ari_u.poc); + NLA_PUT_U32(msg, DECTA_ARI_FPS, ari->ari_fps); + break; + case DECT_ARC_D: + NLA_PUT_U32(msg, DECTA_ARI_GOP, ari->ari_u.gop); + break; + case DECT_ARC_E: + NLA_PUT_U16(msg, DECTA_ARI_FIL, ari->ari_u.fil); + break; + } + nla_nest_end(msg, nla); + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +void nl_dect_dump_ari(const struct nl_dect_ari *ari, struct nl_dump_params *p) +{ + nl_dump(p, "class %c ", 'A' + ari->ari_class); + + switch (ari->ari_class) { + case DECT_ARC_A: + nl_dump(p, "(residential) EMC: %.4x FPN: %.5x", + ari->ari_u.emc, ari->ari_fpn); + break; + case DECT_ARC_B: + nl_dump(p, "(private multiple cell) EIC: %.4x FPN: %.2x FPS: %x", + ari->ari_u.eic, ari->ari_fpn, ari->ari_fps); + break; + case DECT_ARC_C: + nl_dump(p, "(public) POC: %.4x FPN: %.2x FPS: %x", + ari->ari_u.poc, ari->ari_fpn, ari->ari_fps); + break; + case DECT_ARC_D: + nl_dump(p, "(public GSM) GOP: %.5x FPN: %.2x", + ari->ari_u.gop, ari->ari_fpn); + break; + case DECT_ARC_E: + nl_dump(p, "(PP to PP) FIL: %.4x FPN: %.3x", + ari->ari_u.fil, ari->ari_fpn); + } + +} + +static struct trans_tbl ari_classes[] = { + __ADD(DECT_ARC_A, a) + __ADD(DECT_ARC_B, b) + __ADD(DECT_ARC_C, c) + __ADD(DECT_ARC_D, d) + __ADD(DECT_ARC_E, e) +}; + +const char *nl_dect_ari_class2str(enum dect_ari_classes class, char *buf, size_t len) +{ + return __type2str(class, buf, len, ari_classes, ARRAY_SIZE(ari_classes)); +} + +enum dect_ari_classes nl_dect_ari_str2class(const char *str) +{ + return __str2type(str, ari_classes, ARRAY_SIZE(ari_classes)); +} + +void nl_dect_ari_set_class(struct nl_dect_ari *ari, enum dect_ari_classes class) +{ + ari->ari_flags |= ARI_ATTR_CLASS; + ari->ari_class = class; +} + +enum dect_ari_classes nl_dect_ari_get_class(const struct nl_dect_ari *ari) +{ + return ari->ari_class; +} + +void nl_dect_ari_set_fpn(struct nl_dect_ari *ari, uint32_t fpn) +{ + ari->ari_flags |= ARI_ATTR_FPN; + ari->ari_fpn = fpn; +} + +uint32_t nl_dect_ari_get_fpn(const struct nl_dect_ari *ari) +{ + return ari->ari_fpn; +} + +void nl_dect_ari_set_fps(struct nl_dect_ari *ari, uint32_t fps) +{ + ari->ari_flags |= ARI_ATTR_FPS; + ari->ari_fps = fps; +} + +uint32_t nl_dect_ari_get_fps(const struct nl_dect_ari *ari) +{ + return ari->ari_fps; +} + +void nl_dect_ari_set_emc(struct nl_dect_ari *ari, uint16_t emc) +{ + ari->ari_flags |= ARI_ATTR_EMC; + ari->ari_u.emc = emc; +} + +uint16_t nl_dect_ari_get_emc(const struct nl_dect_ari *ari) +{ + return ari->ari_u.emc; +} + +void nl_dect_ari_set_eic(struct nl_dect_ari *ari, uint16_t eic) +{ + ari->ari_flags |= ARI_ATTR_EIC; + ari->ari_u.eic = eic; +} + +uint16_t nl_dect_ari_get_eic(const struct nl_dect_ari *ari) +{ + return ari->ari_u.eic; +} + +void nl_dect_ari_set_poc(struct nl_dect_ari *ari, uint16_t poc) +{ + ari->ari_flags |= ARI_ATTR_POC; + ari->ari_u.poc = poc; +} + +uint16_t nl_dect_ari_get_poc(const struct nl_dect_ari *ari) +{ + return ari->ari_u.poc; +} + +void nl_dect_ari_set_gop(struct nl_dect_ari *ari, uint32_t gop) +{ + ari->ari_flags |= ARI_ATTR_GOP; + ari->ari_u.gop = gop; +} + +uint32_t nl_dect_ari_get_gop(const struct nl_dect_ari *ari) +{ + return ari->ari_u.gop; +} + +void nl_dect_ari_set_fil(struct nl_dect_ari *ari, uint16_t fil) +{ + ari->ari_flags |= ARI_ATTR_FIL; + ari->ari_u.fil = fil; +} + +uint16_t nl_dect_ari_get_fil(const struct nl_dect_ari *ari) +{ + return ari->ari_u.fil; +} diff --git a/lib/dect/cell.c b/lib/dect/cell.c new file mode 100644 index 0000000..f7081d9 --- /dev/null +++ b/lib/dect/cell.c @@ -0,0 +1,267 @@ +/* + * lib/nl_dect/cell.c DECT Cell objects + * + * 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 version 2.1 + * of the License. + * + * Copyright (c) 2009 Patrick McHardy <kaber@trash.net> + */ + +/** + * @ingroup nl_dect + * @defgroup nl_dect Transceivers + * @brief + * @{ + */ + +#include <netlink-private/netlink.h> +#include <netlink/netlink.h> +#include <netlink/utils.h> +#include <netlink/dect/cell.h> +#include <netlink/dect/ari.h> +#include <linux/dect_netlink.h> + +/** @cond SKIP */ +static struct nl_cache_ops nl_dect_cell_ops; +/** @endcond */ + +static struct nla_policy cell_policy[DECTA_CELL_MAX + 1] = { + [DECTA_CELL_NAME] = { .type = NLA_STRING, .maxlen = 16 }, + [DECTA_CELL_FLAGS] = { .type = NLA_U32 }, + [DECTA_CELL_TRANSCEIVERS] = { .type = NLA_NESTED }, + [DECTA_CELL_CLUSTER] = { .type = NLA_U8 }, +}; + +static int cell_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *n, struct nl_parser_param *pp) +{ + struct dectmsg *dm = nlmsg_data(n); + struct nl_dect_cell *cell; + struct nlattr *tb[DECTA_CELL_MAX + 1], *nla; + int rem, err; + + err = nlmsg_parse(n, sizeof(*dm), tb, DECTA_CELL_MAX, cell_policy); + if (err < 0) + return err; + + cell = nl_dect_cell_alloc(); + if (cell == NULL) { + err = -NLE_NOMEM; + goto errout; + } + + cell->ce_msgtype = n->nlmsg_type; + cell->c_index = dm->dm_index; + + if (tb[DECTA_CELL_NAME] != NULL) + nl_dect_cell_set_name(cell, nla_data(tb[DECTA_CELL_NAME])); + if (tb[DECTA_CELL_FLAGS] != NULL) + nl_dect_cell_set_flags(cell, nla_get_u32(tb[DECTA_CELL_FLAGS])); + if (tb[DECTA_CELL_TRANSCEIVERS] != NULL) { + unsigned int i = 0; + nla_for_each_nested(nla, tb[DECTA_CELL_TRANSCEIVERS], rem) { + char *id = nla_strdup(nla); + if (id == NULL) { + err = -NLE_NOMEM; + goto errout; + } + nl_dect_cell_set_transceiver(cell, i++, id); + } + } + if (tb[DECTA_CELL_CLUSTER] != NULL) + nl_dect_cell_set_link(cell, nla_get_u8(tb[DECTA_CELL_CLUSTER])); + + err = pp->pp_cb((struct nl_object *)cell, pp); +errout: + nl_dect_cell_put(cell); + return err; +} + +static int cell_request_update(struct nl_cache *c, struct nl_sock *h) +{ + struct dectmsg dm; + + memset(&dm, 0, sizeof(dm)); + return nl_send_simple(h, DECT_GET_CELL, NLM_F_DUMP, &dm, sizeof(dm)); +} + +/** + * @name Cache Management + * @{ + */ +int nl_dect_cell_alloc_cache(struct nl_sock *sk, struct nl_cache **result) +{ + struct nl_cache *cache; + int err; + + cache = nl_cache_alloc(&nl_dect_cell_ops); + if (cache == NULL) + return -NLE_NOMEM; + + if (sk && (err = nl_cache_refill(sk, cache)) < 0) { + free(cache); + return err; + } + + *result = cache; + return 0; +} + +struct nl_dect_cell *nl_dect_cell_get_by_name(struct nl_cache *cache, const char *name) +{ + struct nl_dect_cell *cell; + + nl_list_for_each_entry(cell, &cache->c_items, ce_list) { + if (!strcmp(cell->c_name, name)) { + nl_object_get((struct nl_object *)cell); + return cell; + } + } + return NULL; +} + +struct nl_dect_cell *nl_dect_cell_get_by_index(struct nl_cache *cache, int index) +{ + struct nl_dect_cell *cell; + + nl_list_for_each_entry(cell, &cache->c_items, ce_list) { + if (cell->c_index == index) { + nl_object_get((struct nl_object *)cell); + return cell; + } + } + return NULL; +} + +/** @} */ + +/** + * @name Device creation + * @{ + */ + +static int build_cell_msg(struct nl_dect_cell *tmpl, int cmd, int flags, + struct nl_msg **result) +{ + struct nl_msg *msg; + int err; + + msg = nlmsg_alloc_simple(cmd, flags); + if (msg == NULL) + return -NLE_NOMEM; + + err = nl_dect_cell_build_msg(msg, tmpl); + if (err < 0) { + nlmsg_free(msg); + return err; + } + + *result = msg; + return 0; +} + +int nl_dect_cell_build_add_request(struct nl_dect_cell *tmpl, int flags, + struct nl_msg **result) +{ + return build_cell_msg(tmpl, DECT_NEW_CELL, NLM_F_CREATE | flags, + result); +} + +int nl_dect_cell_add(struct nl_sock *sk, struct nl_dect_cell *cell, int flags) +{ + struct nl_msg *msg; + int err; + + err = nl_dect_cell_build_add_request(cell, flags, &msg); + if (err < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +int nl_dect_cell_build_del_request(struct nl_dect_cell *tmpl, int flags, + struct nl_msg **result) +{ + return build_cell_msg(tmpl, DECT_DEL_CELL, flags, result); +} + +int nl_dect_cell_delete(struct nl_sock *sk, struct nl_dect_cell *tmpl, int flags) +{ + struct nl_msg *msg; + int err; + + err = nl_dect_cell_build_del_request(tmpl, flags, &msg); + if (err < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** @} */ + +/** + * @name Name <-> Index Translations + * @{ + */ + +char *nl_dect_cell_i2name(struct nl_cache *cache, int index, char *buf, size_t len) +{ + struct nl_dect_cell *cell = nl_dect_cell_get_by_index(cache, index); + + if (cell != NULL) { + strncpy(buf, cell->c_name, len - 1); + buf[len - 1] = 0; + return buf; + } + return NULL; +} + +int nl_dect_cell_name2i(struct nl_cache *cache, const char *name) +{ + struct nl_dect_cell *cell = nl_dect_cell_get_by_name(cache, name); + + if (cell != NULL) + return cell->c_index; + return 0; +} + +/** @} */ + +static struct nl_cache_ops nl_dect_cell_ops = { + .co_name = "nl_dect/cell", + .co_hdrsize = 0, + .co_msgtypes = { + { DECT_NEW_CELL, NL_ACT_NEW, "new" }, + { DECT_DEL_CELL, NL_ACT_NEW, "del" }, + { DECT_GET_CELL, NL_ACT_GET, "get" }, + END_OF_MSGTYPES_LIST + }, + .co_protocol = NETLINK_DECT, + .co_request_update = cell_request_update, + .co_msg_parser = cell_msg_parser, + .co_obj_ops = &nl_dect_cell_obj_ops, +}; + +static void __init cell_init(void) +{ + nl_cache_mngt_register(&nl_dect_cell_ops); +} + +static void __exit cell_exit(void) +{ + nl_cache_mngt_unregister(&nl_dect_cell_ops); +} + +/** @} */ diff --git a/lib/dect/cell_obj.c b/lib/dect/cell_obj.c new file mode 100644 index 0000000..603fef0 --- /dev/null +++ b/lib/dect/cell_obj.c @@ -0,0 +1,234 @@ +/* + * lib/dect/cell.c DECT Cell objects + * + * 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 version 2.1 + * of the License. + * + * Copyright (c) 2009 Patrick McHardy <kaber@trash.net> + */ + +#include <netlink-private/netlink.h> +#include <netlink/netlink.h> +#include <netlink/cache.h> +#include <netlink/utils.h> +#include <netlink/data.h> +#include <netlink/dect/cluster.h> +#include <netlink/dect/cell.h> +#include <netlink/dect/ari.h> +#include <linux/dect_netlink.h> + +/** @cond SKIP */ +#define CELL_ATTR_INDEX 0x0001 +#define CELL_ATTR_NAME 0x0002 +#define CELL_ATTR_FLAGS 0x0004 +#define CELL_ATTR_TRANSCEIVER 0x0008 +#define CELL_ATTR_LINK 0x0010 +/** @endcond */ + +static void cell_free_data(struct nl_object *obj) +{ + struct nl_dect_cell *cell = nl_object_priv(obj); + unsigned int i; + + if (cell == NULL) + return; + for (i = 0; i < 16; i++) + free(cell->c_transceiver[i]); +} + +static void cell_dump(struct nl_object *obj, struct nl_dump_params *p) +{ + struct nl_dect_cell *cell = nl_object_priv(obj); + struct nl_cache *cluster_cache; + unsigned int i; + char buf[64]; + + if (cell->ce_mask & CELL_ATTR_NAME) + nl_dump(p, "%u: DECT Cell %s", cell->c_index, cell->c_name); + + if (cell->ce_mask & CELL_ATTR_LINK) { + cluster_cache = nl_cache_mngt_require("nl_dect/cluster"); + if (cluster_cache != NULL) { + nl_dect_cluster_i2name(cluster_cache, cell->c_link, buf, + sizeof(buf)); + nl_dump(p, "@%s", buf); + } else + nl_dump(p, "@%u", cell->c_link); + } + nl_dump(p, ":"); + + if (cell->ce_mask & CELL_ATTR_FLAGS) { + nl_dect_cell_flags2str(cell->c_flags, buf, sizeof(buf)); + nl_dump(p, " <%s>", buf); + } + nl_dump(p, "\n"); + + if (cell->ce_mask & CELL_ATTR_TRANSCEIVER) { + for (i = 0; i < 16 && cell->c_transceiver[i] != NULL; i++) + nl_dump(p, "\tTransceiver: %s\n", + cell->c_transceiver[i]); + } + +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct nl_dect_cell *nl_dect_cell_alloc(void) +{ + return (struct nl_dect_cell *)nl_object_alloc(&nl_dect_cell_obj_ops); +} + +void nl_dect_cell_get(struct nl_dect_cell *cell) +{ + nl_object_get((struct nl_object *)cell); +} + +void nl_dect_cell_put(struct nl_dect_cell *cell) +{ + nl_object_put((struct nl_object *)cell); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void nl_dect_cell_set_index(struct nl_dect_cell *cell, int index) +{ + cell->c_index = index; + cell->ce_mask |= CELL_ATTR_INDEX; +} + +bool nl_dect_cell_test_index(const struct nl_dect_cell *cell) +{ + return !!(cell->ce_mask & CELL_ATTR_INDEX); +} + +int nl_dect_cell_get_index(const struct nl_dect_cell *cell) +{ + return cell->c_index; +} + +void nl_dect_cell_set_name(struct nl_dect_cell *cell, const char *name) +{ + cell->c_name = strdup(name); + cell->ce_mask |= CELL_ATTR_NAME; +} + +bool nl_dect_cell_test_name(const struct nl_dect_cell *cell) +{ + return !!(cell->ce_mask & CELL_ATTR_NAME); +} + +const char *nl_dect_cell_get_name(const struct nl_dect_cell *cell) +{ + return cell->c_name; +} + +void nl_dect_cell_set_flags(struct nl_dect_cell *cell, uint32_t flags) +{ + cell->c_flags = flags; + cell->ce_mask |= CELL_ATTR_FLAGS; +} + +bool nl_dect_cell_test_flags(const struct nl_dect_cell *cell) +{ + return !!(cell->ce_mask & CELL_ATTR_FLAGS); +} + +uint32_t nl_dect_cell_get_flags(const struct nl_dect_cell *cell) +{ + return cell->c_flags; +} + +void nl_dect_cell_set_transceiver(struct nl_dect_cell *cell, unsigned int i, + const char *id) +{ + cell->c_transceiver[i] = strdup(id); + cell->ce_mask |= CELL_ATTR_TRANSCEIVER; +} + +bool nl_dect_cell_test_transceiver(const struct nl_dect_cell *cell) +{ + return !!(cell->ce_mask & CELL_ATTR_TRANSCEIVER); +} + +const char *nl_dect_cell_get_transceiver(const struct nl_dect_cell *cell, + unsigned int i) +{ + return cell->c_transceiver[i]; +} + +void nl_dect_cell_set_link(struct nl_dect_cell *cell, int link) +{ + cell->c_link = link; + cell->ce_mask |= CELL_ATTR_LINK; +} + +bool nl_dect_cell_test_link(const struct nl_dect_cell *cell) +{ + return !!(cell->ce_mask & CELL_ATTR_LINK); +} + +int nl_dect_cell_get_link(const struct nl_dect_cell *cell) +{ + return cell->c_link; +} + +int nl_dect_cell_build_msg(struct nl_msg *msg, struct nl_dect_cell *cell) +{ + struct dectmsg dm = { + .dm_index = cell->c_index, + }; + + if (nlmsg_append(msg, &dm, sizeof(dm), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + if (cell->ce_mask & CELL_ATTR_NAME) + NLA_PUT_STRING(msg, DECTA_CELL_NAME, cell->c_name); + if (cell->ce_mask & CELL_ATTR_FLAGS) + NLA_PUT_U32(msg, DECTA_CELL_FLAGS, cell->c_flags); + if (cell->ce_mask & CELL_ATTR_LINK) + NLA_PUT_U8(msg, DECTA_CELL_CLUSTER, cell->c_link); + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +static struct trans_tbl cell_flags[] = { + __ADD(DECT_CELL_CCP, ccp) + __ADD(DECT_CELL_SLAVE, slave) + __ADD(DECT_CELL_MONITOR, monitor) +}; + +char *nl_dect_cell_flags2str(uint32_t flags, char *buf, size_t len) +{ + return __flags2str(flags, buf, len, cell_flags, ARRAY_SIZE(cell_flags)); +} + +uint32_t nl_dect_cell_str2flags(const char *str) +{ + return __str2flags(str, cell_flags, ARRAY_SIZE(cell_flags)); +} + +/** @cond SKIP */ +struct nl_object_ops nl_dect_cell_obj_ops = { + .oo_name = "nl_dect/cell", + .oo_size = sizeof(struct nl_dect_cell), + .oo_free_data = cell_free_data, + .oo_dump = { + [NL_DUMP_LINE] = cell_dump, + }, + .oo_id_attrs = CELL_ATTR_NAME, +}; + +/** @endcond */ + +/** @} */ diff --git a/lib/dect/cluster.c b/lib/dect/cluster.c new file mode 100644 index 0000000..29ac522 --- /dev/null +++ b/lib/dect/cluster.c @@ -0,0 +1,417 @@ +/* + * lib/dect/cluster.c DECT Cluster objects + * + * 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 version 2.1 + * of the License. + * + * Copyright (c) 2009 Patrick McHardy <kaber@trash.net> + */ + +/** + * @ingroup nl_dect + * @defgroup nl_dect Transceivers + * @brief + * @{ + */ + +#include <netlink-private/netlink.h> +#include <netlink/netlink.h> +#include <netlink/utils.h> +#include <netlink/dect/cluster.h> +#include <netlink/dect/ari.h> +#include <linux/dect_netlink.h> + +/** @cond SKIP */ +static struct nl_cache_ops nl_dect_cluster_ops; +/** @endcond */ + +static struct nla_policy mbc_tb_policy[DECTA_MBC_TB_MAX + 1] = { + [DECTA_MBC_TB_LBN] = { .type = NLA_U8 }, + [DECTA_MBC_TB_ECN] = { .type = NLA_U8 }, + [DECTA_MBC_TB_CELL] = { .type = NLA_U8 }, + [DECTA_MBC_TB_RX_SLOT] = { .type = NLA_U8 }, + [DECTA_MBC_TB_TX_SLOT] = { .type = NLA_U8 }, +}; + +static int tb_msg_parser(struct nlattr *nla, struct nl_dect_mbc *mbc) +{ + struct nlattr *tb[DECTA_MBC_TB_MAX + 1]; + struct nl_dect_mbc_tb *mtb; + int err; + + if (nla_type(nla) != DECTA_LIST_ELEM) + return -NLE_INVAL; + + err = nla_parse_nested(tb, DECTA_MBC_TB_MAX, nla, mbc_tb_policy); + if (err < 0) + return err; + + mtb = &mbc->mbc_tbs[mbc->mbc_ntbs++]; + if (tb[DECTA_MBC_TB_LBN] != NULL) + mtb->mtb_lbn = nla_get_u8(tb[DECTA_MBC_TB_LBN]); + if (tb[DECTA_MBC_TB_ECN] != NULL) + mtb->mtb_ecn = nla_get_u8(tb[DECTA_MBC_TB_ECN]); + if (tb[DECTA_MBC_TB_CELL] != NULL) + mtb->mtb_cell = nla_get_u8(tb[DECTA_MBC_TB_CELL]); + if (tb[DECTA_MBC_TB_RX_SLOT] != NULL) + mtb->mtb_rx_slot = nla_get_u8(tb[DECTA_MBC_TB_RX_SLOT]); + if (tb[DECTA_MBC_TB_TX_SLOT] != NULL) + mtb->mtb_tx_slot = nla_get_u8(tb[DECTA_MBC_TB_TX_SLOT]); + + return 0; +} + +static struct nla_policy mbc_stats_policy[DECTA_MBC_STATS_MAX + 1] = { + [DECTA_MBC_STATS_CS_RX_BYTES] = { .type = NLA_U32 }, + [DECTA_MBC_STATS_CS_TX_BYTES] = { .type = NLA_U32 }, + [DECTA_MBC_STATS_I_RX_BYTES] = { .type = NLA_U32 }, + [DECTA_MBC_STATS_I_TX_BYTES] = { .type = NLA_U32 }, + [DECTA_MBC_STATS_HANDOVERS] = { .type = NLA_U32 }, +}; + +static int mbc_stats_msg_parser(struct nlattr *nla, struct nl_dect_mbc *mbc) +{ + struct nlattr *tb[DECTA_MBC_STATS_MAX + 1]; + int err; + + err = nla_parse_nested(tb, DECTA_MBC_MAX, nla, mbc_stats_policy); + if (err < 0) + return err; + + if (tb[DECTA_MBC_STATS_CS_RX_BYTES] != NULL) + mbc->mbc_cs_rx_bytes = nla_get_u32(tb[DECTA_MBC_STATS_CS_RX_BYTES]); + if (tb[DECTA_MBC_STATS_CS_TX_BYTES] != NULL) + mbc->mbc_cs_tx_bytes = nla_get_u32(tb[DECTA_MBC_STATS_CS_TX_BYTES]); + if (tb[DECTA_MBC_STATS_I_RX_BYTES] != NULL) + mbc->mbc_i_rx_bytes = nla_get_u32(tb[DECTA_MBC_STATS_I_RX_BYTES]); + if (tb[DECTA_MBC_STATS_I_TX_BYTES] != NULL) + mbc->mbc_i_tx_bytes = nla_get_u32(tb[DECTA_MBC_STATS_I_TX_BYTES]); + if (tb[DECTA_MBC_STATS_HANDOVERS] != NULL) + mbc->mbc_handovers = nla_get_u32(tb[DECTA_MBC_STATS_HANDOVERS]); + return 0; +} + +static struct nla_policy mbc_policy[DECTA_MBC_MAX + 1] = { + [DECTA_MBC_MCEI] = { .type = NLA_U32 }, + [DECTA_MBC_SERVICE] = { .type = NLA_U8 }, + [DECTA_MBC_STATE] = { .type = NLA_U8 }, + [DECTA_MBC_CIPHER_STATE] = { .type = NLA_U8 }, + [DECTA_MBC_TBS] = { .type = NLA_NESTED }, +}; + +static int mbc_msg_parser(struct nlattr *nla, struct nl_dect_cluster *cl) +{ + struct nlattr *tb[DECTA_MBC_MAX + 1]; + struct nl_dect_mbc *mbc; + int err, rem; + + if (nla_type(nla) != DECTA_LIST_ELEM) + return -NLE_INVAL; + + err = nla_parse_nested(tb, DECTA_MBC_MAX, nla, mbc_policy); + if (err < 0) + return err; + + mbc = &cl->cl_mbcs[cl->cl_nmbcs++]; + if (tb[DECTA_MBC_MCEI] != NULL) + mbc->mbc_mcei = nla_get_u32(tb[DECTA_MBC_MCEI]); + if (tb[DECTA_MBC_SERVICE] != NULL) + mbc->mbc_service = nla_get_u8(tb[DECTA_MBC_SERVICE]); + if (tb[DECTA_MBC_STATE] != NULL) + mbc->mbc_state = nla_get_u8(tb[DECTA_MBC_STATE]); + if (tb[DECTA_MBC_CIPHER_STATE] != NULL) + mbc->mbc_cipher_state = nla_get_u8(tb[DECTA_MBC_CIPHER_STATE]); + if (tb[DECTA_MBC_STATS] != NULL) { + err = mbc_stats_msg_parser(tb[DECTA_MBC_STATS], mbc); + if (err < 0) + return err; + } + if (tb[DECTA_MBC_TBS] != NULL) { + nla_for_each_nested(nla, tb[DECTA_MBC_TBS], rem) { + err = tb_msg_parser(nla, mbc); + if (err < 0) + return err; + } + } + return 0; +} + +static struct nla_policy cluster_policy[DECTA_CLUSTER_MAX + 1] = { + [DECTA_CLUSTER_NAME] = { .type = NLA_STRING, .maxlen = 16 }, + [DECTA_CLUSTER_MODE] = { .type = NLA_U8 }, + [DECTA_CLUSTER_PARI] = { .type = NLA_NESTED }, + [DECTA_CLUSTER_CELLS] = { .type = NLA_NESTED }, + [DECTA_CLUSTER_MBCS] = { .type = NLA_NESTED }, +}; + +static int cluster_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *n, struct nl_parser_param *pp) +{ + struct dectmsg *dm = nlmsg_data(n); + struct nl_dect_cluster *cl; + struct nlattr *tb[DECTA_CLUSTER_MAX + 1], *nla; + int err, rem; + + err = nlmsg_parse(n, sizeof(*dm), tb, DECTA_CLUSTER_MAX, cluster_policy); + if (err < 0) + return err; + + cl = nl_dect_cluster_alloc(); + if (cl == NULL) { + err = -NLE_NOMEM; + goto errout; + } + + cl->ce_msgtype = n->nlmsg_type; + cl->cl_index = dm->dm_index; + + if (tb[DECTA_CLUSTER_NAME] != NULL) { + char *name = nla_strdup(tb[DECTA_CLUSTER_NAME]); + if (name == NULL) { + err = -NLE_NOMEM; + goto errout; + } + nl_dect_cluster_set_name(cl, name); + free(name); + } + + if (tb[DECTA_CLUSTER_MODE] != NULL) + nl_dect_cluster_set_mode(cl, nla_get_u8(tb[DECTA_CLUSTER_MODE])); + + if (tb[DECTA_CLUSTER_PARI] != NULL) { + struct nl_dect_ari pari; + + err = nl_dect_parse_ari(&pari, tb[DECTA_CLUSTER_PARI]); + if (err < 0) + goto errout; + nl_dect_cluster_set_pari(cl, &pari); + } + + if (tb[DECTA_CLUSTER_MBCS] != NULL) { + nla_for_each_nested(nla, tb[DECTA_CLUSTER_MBCS], rem) { + err = mbc_msg_parser(nla, cl); + if (err < 0) + goto errout; + } + } + + err = pp->pp_cb((struct nl_object *)cl, pp); +errout: + nl_dect_cluster_put(cl); + return err; +} + +static int cluster_request_update(struct nl_cache *c, struct nl_sock *h) +{ + struct dectmsg dm; + + memset(&dm, 0, sizeof(dm)); + return nl_send_simple(h, DECT_GET_CLUSTER, NLM_F_DUMP, &dm, sizeof(dm)); +} + +/** + * @name Cache Management + * @{ + */ +int nl_dect_cluster_alloc_cache(struct nl_sock *sk, struct nl_cache **result) +{ + struct nl_cache *cache; + int err; + + cache = nl_cache_alloc(&nl_dect_cluster_ops); + if (cache == NULL) + return -NLE_NOMEM; + + if (sk && (err = nl_cache_refill(sk, cache)) < 0) { + free(cache); + return err; + } + + *result = cache; + return 0; +} + +struct nl_dect_cluster *nl_dect_cluster_get_by_name(struct nl_cache *cache, + const char *name) +{ + struct nl_dect_cluster *cl; + + nl_list_for_each_entry(cl, &cache->c_items, ce_list) { + if (!strcmp(cl->cl_name, name)) { + nl_object_get((struct nl_object *)cl); + return cl; + } + } + return NULL; +} + +struct nl_dect_cluster *nl_dect_cluster_get_by_index(struct nl_cache *cache, int index) +{ + struct nl_dect_cluster *cl; + + nl_list_for_each_entry(cl, &cache->c_items, ce_list) { + if (cl->cl_index == index) { + nl_object_get((struct nl_object *)cl); + return cl; + } + } + return NULL; +} + +/** @} */ + +/** + * @name Device creation + * @{ + */ + +static int build_cluster_msg(struct nl_dect_cluster *tmpl, int cmd, int flags, + struct nl_msg **result) +{ + struct nl_msg *msg; + int err; + + msg = nlmsg_alloc_simple(cmd, flags); + if (msg == NULL) + return -NLE_NOMEM; + + err = nl_dect_cluster_build_msg(msg, tmpl); + if (err < 0) { + nlmsg_free(msg); + return err; + } + + *result = msg; + return 0; +} + +int nl_dect_cluster_build_add_request(struct nl_dect_cluster *tmpl, int flags, + struct nl_msg **result) +{ + return build_cluster_msg(tmpl, DECT_NEW_CLUSTER, NLM_F_CREATE | flags, + result); +} + +int nl_dect_cluster_add(struct nl_sock *sk, struct nl_dect_cluster *cl, int flags) +{ + struct nl_msg *msg; + int err; + + err = nl_dect_cluster_build_add_request(cl, flags, &msg); + if (err < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +int nl_dect_cluster_build_del_request(struct nl_dect_cluster *tmpl, int flags, + struct nl_msg **result) +{ + return build_cluster_msg(tmpl, DECT_DEL_CLUSTER, flags, result); +} + +int nl_dect_cluster_delete(struct nl_sock *sk, struct nl_dect_cluster *tmpl, int flags) +{ + struct nl_msg *msg; + int err; + + err = nl_dect_cluster_build_del_request(tmpl, flags, &msg); + if (err < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +int nl_dect_cluster_build_query_request(struct nl_dect_cluster *tmpl, int flags, + struct nl_msg **result) +{ + return build_cluster_msg(tmpl, DECT_GET_CLUSTER, flags, result); +} + +int nl_dect_cluster_query(struct nl_sock *sk, struct nl_dect_cluster *cl, int flags) +{ + struct nl_msg *msg; + int err; + + err = nl_dect_cluster_build_query_request(cl, flags, &msg); + if (err < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** @} */ + +/** + * @name Name <-> Index Translations + * @{ + */ + +char *nl_dect_cluster_i2name(struct nl_cache *cache, int index, + char *buf, size_t len) +{ + struct nl_dect_cluster *cl = nl_dect_cluster_get_by_index(cache, index); + + if (cl != NULL) { + strncpy(buf, cl->cl_name, len - 1); + buf[len - 1] = 0; + return buf; + } + + return NULL; +} + +int nl_dect_cluster_name2i(struct nl_cache *cache, const char *name) +{ + struct nl_dect_cluster *cl = nl_dect_cluster_get_by_name(cache, name); + + if (cl != NULL) + return cl->cl_index; + return 0; +} + +/** @} */ + +static struct nl_cache_ops nl_dect_cluster_ops = { + .co_name = "nl_dect/cluster", + .co_hdrsize = 0, + .co_msgtypes = { + { DECT_NEW_CLUSTER, NL_ACT_NEW, "new" }, + { DECT_DEL_CLUSTER, NL_ACT_NEW, "del" }, + { DECT_GET_CLUSTER, NL_ACT_GET, "get" }, + END_OF_MSGTYPES_LIST + }, + .co_protocol = NETLINK_DECT, + .co_request_update = cluster_request_update, + .co_msg_parser = cluster_msg_parser, + .co_obj_ops = &nl_dect_cluster_obj_ops, +}; + +static void __init cluster_init(void) +{ + nl_cache_mngt_register(&nl_dect_cluster_ops); +} + +static void __exit cluster_exit(void) +{ + nl_cache_mngt_unregister(&nl_dect_cluster_ops); +} + +/** @} */ diff --git a/lib/dect/cluster_obj.c b/lib/dect/cluster_obj.c new file mode 100644 index 0000000..043c677 --- /dev/null +++ b/lib/dect/cluster_obj.c @@ -0,0 +1,274 @@ +/* + * lib/dect/cluster.c DECT Cluster objects + * + * 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 version 2.1 + * of the License. + * + * Copyright (c) 2009 Patrick McHardy <kaber@trash.net> + */ + +#include <netlink-private/netlink.h> +#include <netlink/netlink.h> +#include <netlink/cache.h> +#include <netlink/utils.h> +#include <netlink/data.h> +#include <netlink/dect/cluster.h> +#include <netlink/dect/ari.h> +#include <linux/dect_netlink.h> +#include <linux/dect.h> + +/** @cond SKIP */ +#define CL_ATTR_NAME 0x0001 +#define CL_ATTR_MODE 0x0002 +#define CL_ATTR_PARI 0x0004 +/** @endcond */ + +char *nl_dect_mbc_state2string(enum dect_mbc_state state, + char *buf, size_t len); +char *nl_dect_mbc_service2string(enum dect_mac_service_types type, + char *buf, size_t len); +char *nl_dect_mbc_cipher2string(enum dect_cipher_states state, + char *buf, size_t len); + +static void cluster_free_data(struct nl_object *obj) +{ + struct nl_dect_cluster *cl = nl_object_priv(obj); + + if (cl == NULL) + return; + free(cl->cl_name); +} + +static void mbc_tb_dump(struct nl_dect_mbc_tb *mtb, struct nl_dump_params *p) +{ + nl_dump(p, "\t TB: LBN: %u ECN: %u Cell: %u RX/TX-Slots: %u/%u\n", + mtb->mtb_lbn, mtb->mtb_ecn, + mtb->mtb_cell, mtb->mtb_rx_slot, mtb->mtb_tx_slot); +} + +static void mbc_dump(struct nl_dect_mbc *mbc, struct nl_dump_params *p) +{ + unsigned int i; + char buf[64]; + + nl_dump(p, "\tMBC: MCEI %u\n", mbc->mbc_mcei); + nl_dump(p, "\t State: %s\n", + nl_dect_mbc_state2string(mbc->mbc_state, + buf, sizeof(buf))); + nl_dump(p, "\t Service: %s\n", + nl_dect_mbc_service2string(mbc->mbc_service, + buf, sizeof(buf))); + nl_dump(p, "\t Cipher state: %s\n", + nl_dect_mbc_cipher2string(mbc->mbc_cipher_state, + buf, sizeof(buf))); + nl_dump(p, "\t Cs-channel RX-Bytes: %u TX-Bytes: %u\n", + mbc->mbc_cs_rx_bytes, mbc->mbc_cs_tx_bytes); + nl_dump(p, "\t I-channel RX-Bytes: %u TX-Bytes: %u\n", + mbc->mbc_i_rx_bytes, mbc->mbc_i_tx_bytes); + + for (i = 0; i < mbc->mbc_ntbs; i++) + mbc_tb_dump(&mbc->mbc_tbs[i], p); +} + +static void cluster_dump(struct nl_object *obj, struct nl_dump_params *p) +{ + struct nl_dect_cluster *cl = nl_object_priv(obj); + unsigned int i; + char buf[64]; + + if (cl->ce_mask & CL_ATTR_NAME) + nl_dump_line(p, "%d: DECT Cluster %s:\n", + cl->cl_index, cl->cl_name); + + if (cl->ce_mask & CL_ATTR_MODE) + nl_dump_line(p, "\tMode: %s\n", + nl_dect_cluster_mode2str(cl->cl_mode, + buf, sizeof(buf))); + + if (cl->ce_mask & CL_ATTR_PARI) { + nl_dump(p, "\tPARI: "); + nl_dect_dump_ari(&cl->cl_pari, p); + nl_dump(p, "\n"); + } + + nl_dump(p, "\n"); + for (i = 0; i < cl->cl_nmbcs; i++) + mbc_dump(&cl->cl_mbcs[i], p); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct nl_dect_cluster *nl_dect_cluster_alloc(void) +{ + return (struct nl_dect_cluster *)nl_object_alloc(&nl_dect_cluster_obj_ops); +} + +void nl_dect_cluster_get(struct nl_dect_cluster *cl) +{ + nl_object_get((struct nl_object *)cl); +} + +void nl_dect_cluster_put(struct nl_dect_cluster *cl) +{ + nl_object_put((struct nl_object *)cl); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +unsigned int nl_dect_cluster_get_index(const struct nl_dect_cluster *cl) +{ + return cl->cl_index; +} + +void nl_dect_cluster_set_name(struct nl_dect_cluster *cl, const char *name) +{ + cl->cl_name = strdup(name); + cl->ce_mask |= CL_ATTR_NAME; +} + +bool nl_dect_cluster_test_name(const struct nl_dect_cluster *cl) +{ + return !!(cl->ce_mask & CL_ATTR_NAME); +} + +const char *nl_dect_cluster_get_name(const struct nl_dect_cluster *cl) +{ + return cl->cl_name; +} + +void nl_dect_cluster_set_mode(struct nl_dect_cluster *cl, uint8_t mode) +{ + cl->cl_mode = mode; + cl->ce_mask |= CL_ATTR_MODE; +} + +bool nl_dect_cluster_test_mode(const struct nl_dect_cluster *cl) +{ + return !!(cl->ce_mask & CL_ATTR_MODE); +} + +uint8_t nl_dect_cluster_get_mode(const struct nl_dect_cluster *cl) +{ + return cl->cl_mode; +} + +void nl_dect_cluster_set_pari(struct nl_dect_cluster *cl, const struct nl_dect_ari *pari) +{ + memcpy(&cl->cl_pari, pari, sizeof(cl->cl_pari)); + cl->ce_mask |= CL_ATTR_PARI; +} + +bool nl_dect_cluster_test_pari(const struct nl_dect_cluster *cl) +{ + return !!(cl->ce_mask & CL_ATTR_PARI); +} + +const struct nl_dect_ari *nl_dect_cluster_get_pari(const struct nl_dect_cluster *cl) +{ + return &cl->cl_pari; +} + +int nl_dect_cluster_build_msg(struct nl_msg *msg, struct nl_dect_cluster *cl) +{ + struct dectmsg dm = { + .dm_index = cl->cl_index, + }; + + if (nlmsg_append(msg, &dm, sizeof(dm), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + if (cl->ce_mask & CL_ATTR_NAME) + NLA_PUT_STRING(msg, DECTA_CLUSTER_NAME, cl->cl_name); + if (nl_dect_fill_ari(msg, &cl->cl_pari, DECTA_CLUSTER_PARI) < 0) + goto nla_put_failure; + if (cl->ce_mask & CL_ATTR_MODE) + NLA_PUT_U8(msg, DECTA_CLUSTER_MODE, cl->cl_mode); + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +static struct trans_tbl cluster_modes[] = { + __ADD(DECT_MODE_FP, FP) + __ADD(DECT_MODE_PP, PP) +}; + +char *nl_dect_cluster_mode2str(enum dect_cluster_modes mode, char *buf, size_t len) +{ + return __type2str(mode, buf, len, cluster_modes, + ARRAY_SIZE(cluster_modes)); +} + +enum dect_cluster_modes nl_dect_cluster_str2mode(const char *str) +{ + return __str2type(str, cluster_modes, ARRAY_SIZE(cluster_modes)); +} + +static struct trans_tbl mbc_states[] = { + __ADD(DECT_MBC_NONE, none) + __ADD(DECT_MBC_INITIATED, initiated) + __ADD(DECT_MBC_ESTABLISHED, established) + __ADD(DECT_MBC_RELEASED, released) +}; + +char *nl_dect_mbc_state2string(enum dect_mbc_state state, + char *buf, size_t len) +{ + return __type2str(state, buf, len, mbc_states, + ARRAY_SIZE(mbc_states)); +} + +static struct trans_tbl mac_service_types[] = { + __ADD(DECT_SERVICE_IN_MIN_DELAY, IN_min_delay) + __ADD(DECT_SERVICE_IPX_ENCODED_PROTECTED, IPX_encoded_protected) + __ADD(DECT_SERVICE_IN_NORMAL_DELAY, IN_normal_delay) + __ADD(DECT_SERVICE_UNKNOWN, unknown) + __ADD(DECT_SERVICE_C_CHANNEL_ONLY, C_channel_only) + __ADD(DECT_SERVICE_IP_ERROR_DETECTION, IP_error_detection) + __ADD(DECT_SERVICE_IPQ_ERROR_DETECTION, IPQ_error_detection) +}; + +char *nl_dect_mbc_service2string(enum dect_mac_service_types type, + char *buf, size_t len) +{ + return __type2str(type, buf, len, mac_service_types, + ARRAY_SIZE(mac_service_types)); +} + +static struct trans_tbl cipher_states[] = { + __ADD(DECT_CIPHER_DISABLED, disabled) + __ADD(DECT_CIPHER_ENABLED, enabled) +}; + +char *nl_dect_mbc_cipher2string(enum dect_cipher_states state, + char *buf, size_t len) +{ + return __type2str(state, buf, len, cipher_states, + ARRAY_SIZE(cipher_states)); +} + +/** @cond SKIP */ +struct nl_object_ops nl_dect_cluster_obj_ops = { + .oo_name = "nl_dect/cluster", + .oo_size = sizeof(struct nl_dect_cluster), + .oo_free_data = cluster_free_data, + .oo_dump = { + [NL_DUMP_LINE] = cluster_dump, + }, + .oo_id_attrs = CL_ATTR_NAME, +}; + +/** @endcond */ + +/** @} */ diff --git a/lib/dect/dect.c b/lib/dect/dect.c new file mode 100644 index 0000000..c7fbc18 --- /dev/null +++ b/lib/dect/dect.c @@ -0,0 +1,22 @@ +/* + * lib/dect/dect.c DECT + * + * 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 version 2.1 + * of the License. + * + * Copyright (c) 2009 Patrick McHardy <kaber@trash.net> + */ + +#include <netlink-private/netlink.h> +#include <netlink/netlink.h> +#include <netlink/utils.h> +#include <netlink/dect/dect.h> + +double nl_dect_rssi_to_dbm(uint8_t rssi) +{ + if (rssi == 0) + return 0; + return -93 + (rssi * 60.0 / 255); +} diff --git a/lib/dect/llme.c b/lib/dect/llme.c new file mode 100644 index 0000000..baed29e --- /dev/null +++ b/lib/dect/llme.c @@ -0,0 +1,776 @@ +/* + * lib/dect/llme.c DECT Lower Layer Management Entity Objects + * + * 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 version 2.1 + * of the License. + * + * Copyright (c) 2009 Patrick McHardy <kaber@trash.net> + */ + +/** + * @ingroup dect + * @defgroup dect LLME + * @brief + * @{ + */ + +#include <netlink-private/netlink.h> +#include <netlink/netlink.h> +#include <netlink/utils.h> +#include <netlink/dect/dect.h> +#include <netlink/dect/ari.h> +#include <netlink/dect/llme.h> +#include <linux/dect_netlink.h> + +/** @cond SKIP */ +static struct nl_object_ops llme_msg_obj_ops; +/** @endcond */ + +#define MAC_INFO_ATTR_PARI 0x0010000 +#define MAC_INFO_ATTR_RPN 0x0020000 +#define MAC_INFO_ATTR_RSSI 0x0040000 +#define MAC_INFO_ATTR_FPC 0x0080000 +#define MAC_INFO_ATTR_HLC 0x0100000 +#define MAC_INFO_ATTR_EFPC 0x0200000 +#define MAC_INFO_ATTR_EHLC 0x0400000 +#define MAC_INFO_ATTR_EFPC2 0x0800000 +#define MAC_INFO_ATTR_EHLC2 0x1000000 +#define MAC_INFO_ATTR_MFN 0x2000000 + +static inline struct nl_dect_llme_mac_info *mac_info(const struct nl_dect_llme_msg *lmsg) +{ + return (void *)&lmsg->lm_mi; +} + +void nl_dect_llme_mac_info_set_pari(struct nl_dect_llme_msg *lmsg, + const struct nl_dect_ari *pari) +{ + struct nl_dect_llme_mac_info *mi = mac_info(lmsg); + + memcpy(&mi->mi_pari, pari, sizeof(mi->mi_pari)); + lmsg->ce_mask |= MAC_INFO_ATTR_PARI; +} + +bool nl_dect_llme_mac_info_test_pari(const struct nl_dect_llme_msg *lmsg) +{ + return !!(lmsg->ce_mask & MAC_INFO_ATTR_PARI); +} + +const struct nl_dect_ari *nl_dect_llme_mac_info_get_pari(const struct nl_dect_llme_msg *lmsg) +{ + return &mac_info(lmsg)->mi_pari; +} + +void nl_dect_llme_mac_info_set_rpn(struct nl_dect_llme_msg *lmsg, uint8_t rpn) +{ + mac_info(lmsg)->mi_rpn = rpn; + lmsg->ce_mask |= MAC_INFO_ATTR_RPN; +} + +uint8_t nl_dect_llme_mac_info_get_rpn(const struct nl_dect_llme_msg *lmsg) +{ + return mac_info(lmsg)->mi_rpn; +} + +void nl_dect_llme_mac_info_set_rssi(struct nl_dect_llme_msg *lmsg, uint8_t rssi) +{ + mac_info(lmsg)->mi_rssi = rssi; + lmsg->ce_mask |= MAC_INFO_ATTR_RSSI; +} + +uint8_t nl_dect_llme_mac_info_get_rssi(const struct nl_dect_llme_msg *lmsg) +{ + return mac_info(lmsg)->mi_rssi; +} + +void nl_dect_llme_mac_info_set_fpc(struct nl_dect_llme_msg *lmsg, uint32_t fpc) +{ + mac_info(lmsg)->mi_fpc = fpc; + lmsg->ce_mask |= MAC_INFO_ATTR_FPC; +} + +uint32_t nl_dect_llme_mac_info_get_fpc(const struct nl_dect_llme_msg *lmsg) +{ + return mac_info(lmsg)->mi_fpc; +} + +void nl_dect_llme_mac_info_set_hlc(struct nl_dect_llme_msg *lmsg, uint16_t hlc) +{ + mac_info(lmsg)->mi_hlc = hlc; + lmsg->ce_mask |= MAC_INFO_ATTR_HLC; +} + +uint16_t nl_dect_llme_mac_info_get_hlc(const struct nl_dect_llme_msg *lmsg) +{ + return mac_info(lmsg)->mi_hlc; +} + +void nl_dect_llme_mac_info_set_efpc(struct nl_dect_llme_msg *lmsg, uint16_t efpc) +{ + mac_info(lmsg)->mi_efpc = efpc; + lmsg->ce_mask |= MAC_INFO_ATTR_EFPC; +} + +uint16_t nl_dect_llme_mac_info_get_efpc(const struct nl_dect_llme_msg *lmsg) +{ + return mac_info(lmsg)->mi_efpc; +} + +void nl_dect_llme_mac_info_set_ehlc(struct nl_dect_llme_msg *lmsg, uint32_t ehlc) +{ + mac_info(lmsg)->mi_ehlc = ehlc; + lmsg->ce_mask |= MAC_INFO_ATTR_EHLC; +} + +uint32_t nl_dect_llme_mac_info_get_ehlc(const struct nl_dect_llme_msg *lmsg) +{ + return mac_info(lmsg)->mi_ehlc; +} + +void nl_dect_llme_mac_info_set_efpc2(struct nl_dect_llme_msg *lmsg, uint16_t efpc2) +{ + mac_info(lmsg)->mi_efpc2 = efpc2; + lmsg->ce_mask |= MAC_INFO_ATTR_EFPC2; +} + +uint16_t nl_dect_llme_mac_info_get_efpc2(const struct nl_dect_llme_msg *lmsg) +{ + return mac_info(lmsg)->mi_efpc2; +} + +void nl_dect_llme_mac_info_set_ehlc2(struct nl_dect_llme_msg *lmsg, uint32_t ehlc2) +{ + mac_info(lmsg)->mi_ehlc2 = ehlc2; + lmsg->ce_mask |= MAC_INFO_ATTR_EHLC2; +} + +uint32_t nl_dect_llme_mac_info_get_ehlc2(const struct nl_dect_llme_msg *lmsg) +{ + return mac_info(lmsg)->mi_ehlc2; +} + +void nl_dect_llme_mac_info_set_mfn(struct nl_dect_llme_msg *lmsg, uint32_t mfn) +{ + mac_info(lmsg)->mi_mfn = mfn; + lmsg->ce_mask |= MAC_INFO_ATTR_MFN; +} + +uint32_t nl_dect_llme_mac_info_get_mfn(const struct nl_dect_llme_msg *lmsg) +{ + return mac_info(lmsg)->mi_mfn; +} + + +static struct trans_tbl fixed_part_capabilities[] = { + __ADD(DECT_FPC_EXTENDED_FP_INFO, extended_fp_info) + __ADD(DECT_FPC_DOUBLE_DUPLEX_BEARER_CONNECTION, double_duplex_bearer_connection) + __ADD(DECT_FPC_RESERVED, reserved) + __ADD(DECT_FPC_DOUBLE_SLOT, double_slot) + __ADD(DECT_FPC_HALF_SLOT, half_slot) + __ADD(DECT_FPC_FULL_SLOT, full_slot) + __ADD(DECT_FPC_FREQ_CONTROL, frequency_control) + __ADD(DECT_FPC_PAGE_REPETITION, page_repetition) + __ADD(DECT_FPC_CO_SETUP_ON_DUMMY, co_setup_on_dummy) + __ADD(DECT_FPC_CL_UPLINK, cl_uplink) + __ADD(DECT_FPC_CL_DOWNLINK, cl_downlink) + __ADD(DECT_FPC_BASIC_A_FIELD_SETUP, basic_a_field_setup) + __ADD(DECT_FPC_ADV_A_FIELD_SETUP, advanced_a_field_setup) + __ADD(DECT_FPC_B_FIELD_SETUP, b_field_setup) + __ADD(DECT_FPC_CF_MESSAGES, cf_messages) + __ADD(DECT_FPC_IN_MIN_DELAY, in_min_delay) + __ADD(DECT_FPC_IN_NORM_DELAY, in_normal_delay) + __ADD(DECT_FPC_IP_ERROR_DETECTION, ip_error_detection) + __ADD(DECT_FPC_IP_ERROR_CORRECTION, ip_error_correction) + __ADD(DECT_FPC_MULTIBEARER_CONNECTIONS, multibearer_connections) +}; + +char *nl_dect_llme_fpc2str(uint32_t fpc, char *buf, size_t len) +{ + return __flags2str(fpc, buf, len, fixed_part_capabilities, + ARRAY_SIZE(fixed_part_capabilities)); +} + +uint32_t nl_dect_llme_str2fpc(const char *str) +{ + return __str2flags(str, fixed_part_capabilities, + ARRAY_SIZE(fixed_part_capabilities)); +} + +static struct trans_tbl higher_layer_capabilities[] = { + __ADD(DECT_HLC_ADPCM_G721_VOICE, adpcm_g721_voice) + __ADD(DECT_HLC_GAP_PAP_BASIC_SPEECH, gap_pap_basic_speech) + __ADD(DECT_HLC_NON_VOICE_CIRCUIT_SWITCHED, non_voice_circuit_switched_service) + __ADD(DECT_HLC_NON_VOICE_PACKET_SWITCHED, non_voice_packet_switched_service) + __ADD(DECT_HLC_STANDARD_AUTHENTICATION, standard_authentication) + __ADD(DECT_HLC_STANDARD_CIPHERING, standard_ciphering) + __ADD(DECT_HLC_LOCATION_REGISTRATION, location_registration) + __ADD(DECT_HLC_SIM_SERVICES, sim_services) + __ADD(DECT_HLC_NON_STATIC_FIXED_PART, non_static_fixed_part) + __ADD(DECT_HLC_CISS_SERVICE, ciss_service) + __ADD(DECT_HLC_CLMS_SERVICE, clms_service) + __ADD(DECT_HLC_COMS_SERVICE, coms_service) + __ADD(DECT_HLC_ACCESS_RIGHTS_REQUESTS, access_rights_requests) + __ADD(DECT_HLC_EXTERNAL_HANDOVER, external_handover) + __ADD(DECT_HLC_CONNECTION_HANDOVER, connection_handover) + __ADD(DECT_HLC_RESERVED, reserved) +}; + +char *nl_dect_llme_hlc2str(uint16_t hlc, char *buf, size_t len) +{ + return __flags2str(hlc, buf, len, higher_layer_capabilities, + ARRAY_SIZE(higher_layer_capabilities)); +} + +uint16_t nl_dect_llme_str2hlc(const char *str) +{ + return __str2flags(str, higher_layer_capabilities, + ARRAY_SIZE(higher_layer_capabilities)); +} + +static struct trans_tbl extended_fixed_part_capabilities[] = { + __ADD(DECT_EFPC_SYNC_PROLONGED_PREAMBLE, prolonged_preamble) + __ADD(DECT_EFPC_MAC_SUSPEND_RESUME, suspend_resume) + __ADD(DECT_EFPC_MAC_IP_Q_SERVICE, ip_q_service) + __ADD(DECT_EFPC_EXTENDED_FP_INFO2, extended_fp_info2) +}; + +char *nl_dect_llme_efpc2str(uint16_t efpc, char *buf, size_t len) +{ + return __flags2str(efpc, buf, len, extended_fixed_part_capabilities, + ARRAY_SIZE(extended_fixed_part_capabilities)); +} + +uint16_t nl_dect_llme_str2efpc(const char *str) +{ + return __str2flags(str, extended_fixed_part_capabilities, + ARRAY_SIZE(extended_fixed_part_capabilities)); +} +static struct trans_tbl extended_higher_layer_capabilities[] = { + __ADD(DECT_EHLC_ISDN_DATA_SERVICE, isdn_data_service) + __ADD(DECT_EHLC_DPRS_FREL, dprs_frel) + __ADD(DECT_EHLC_DPRS_STREAM, dprs_stream) + __ADD(DECT_EHLC_DATA_SERVICE_PROFILE_D, data_service_profile_d) + __ADD(DECT_EHLC_LRMS, lrms) + __ADD(DECT_EHLC_ASYMETRIC_BEARERS, asymetric_bearers) + __ADD(DECT_EHLC_EMERGENCY_CALLS, emergency_calls) + __ADD(DECT_EHLC_TPUI_LOCATION_REGISTRATION, tpui_location_registration) + __ADD(DECT_EHLC_GPS_SYNCHRONIZED, gps_synchronized) + __ADD(DECT_EHLC_ISDN_INTERMEDIATE_SYSTEM, isdn_intermediate_system) + __ADD(DECT_EHLC_RAP_PART_1_PROFILE, rap_1_profile) + __ADD(DECT_EHLC_V_24, v_24) + __ADD(DECT_EHLC_PPP, ppp) + __ADD(DECT_EHLC_IP, ip) + __ADD(DECT_EHLC_TOKEN_RING, token_ring) + __ADD(DECT_EHLC_ETHERNET, ethernet) + __ADD(DECT_EHLC_IP_ROAMING, ip_roaming) + __ADD(DECT_EHLC_GENERIC_MEDIA_ENCAPSULATION, generic_media_encapsulation) + __ADD(DECT_EHLC_BASIC_ODAP, basic_odap) + __ADD(DECT_EHLC_F_MMS_INTERWORKING_PROFILE, mms_interworking_profile) +}; + +char *nl_dect_llme_ehlc2str(uint32_t ehlc, char *buf, size_t len) +{ + return __flags2str(ehlc, buf, len, extended_higher_layer_capabilities, + ARRAY_SIZE(extended_higher_layer_capabilities)); +} + +uint32_t nl_dect_llme_str2ehlc(const char *str) +{ + return __str2flags(str, extended_higher_layer_capabilities, + ARRAY_SIZE(extended_higher_layer_capabilities)); +} + +static struct trans_tbl extended_fixed_part_capabilities2[] = { + __ADD(DECT_EFPC2_NO_EMISSION_CARRIER, no_emission_carrier) + __ADD(DECT_EFPC2_GF, gf_channel) + __ADD(DECT_EFPC2_SI_PF, si_pf_channel) + __ADD(DECT_EFPC2_IP_F, ip_f_channel) + __ADD(DECT_EFPC2_LONG_SLOT_J672, long_slot_j672) + __ADD(DECT_EFPC2_LONG_SLOT_J640, long_slot_j640) +}; + +char *nl_dect_llme_efpc22str(uint16_t efpc2, char *buf, size_t len) +{ + return __flags2str(efpc2, buf, len, extended_fixed_part_capabilities2, + ARRAY_SIZE(extended_fixed_part_capabilities2)); +} + +uint16_t nl_dect_llme_str2efpc2(const char *str) +{ + return __str2flags(str, extended_fixed_part_capabilities2, + ARRAY_SIZE(extended_fixed_part_capabilities2)); +} + +static struct trans_tbl extended_higher_layer_capabilities2[] = { + __ADD(DECT_EHLC2_NG_DECT_PERMANENT_CLIR, permanent_clir) + __ADD(DECT_EHLC2_NG_DECT_MULTIPLE_CALLS, multiple_calls) + __ADD(DECT_EHLC2_NG_DECT_MULTIPLE_LINES, multiple_lines) + __ADD(DECT_EHLC2_EASY_PAIRING, easy_pairing) + __ADD(DECT_EHLC2_LIST_ACCESS_FEATURES, list_access_features) + __ADD(DECT_EHLC2_NO_EMISSION_MODE, no_emission_mode) + __ADD(DECT_EHLC2_NG_DECT_CALL_DEFLECTION, call_deflection) + __ADD(DECT_EHLC2_NG_DECT_INTRUSION_CALL, intrusion_call) + __ADD(DECT_EHLC2_NG_DECT_CONFERENCE_CALL, conference_call) + __ADD(DECT_EHLC2_NG_DECT_PARALLEL_CALLS, parallel_calls) + __ADD(DECT_EHLC2_NG_DECT_CALL_TRANSFER, call_transfer) + __ADD(DECT_EHLC2_NG_DECT_EXTENDED_WIDEBAND, extended_wideband) + __ADD(DECT_EHLC2_PACKET_DATA_CATEGORY_MASK, packet_data) + __ADD(DECT_EHLC2_NG_DECT_WIDEBAND, wideband) +}; + +char *nl_dect_llme_ehlc22str(uint32_t ehlc2, char *buf, size_t len) +{ + return __flags2str(ehlc2, buf, len, extended_higher_layer_capabilities2, + ARRAY_SIZE(extended_higher_layer_capabilities2)); +} + +uint32_t nl_dect_llme_str22ehlc(const char *str) +{ + return __str2flags(str, extended_higher_layer_capabilities2, + ARRAY_SIZE(extended_higher_layer_capabilities2)); +} + + +static void nl_dect_llme_mac_info_dump(const struct nl_dect_llme_msg *lmsg, + struct nl_dump_params *p) +{ + const struct nl_dect_llme_mac_info *mi = mac_info(lmsg); + char buf[256]; + + if (lmsg->ce_mask & MAC_INFO_ATTR_PARI) { + nl_dump(p, "\n\tARI: "); + nl_dect_dump_ari(&mi->mi_pari, p); + } + if (lmsg->ce_mask & MAC_INFO_ATTR_RPN) + nl_dump(p, " RPN: %x", mi->mi_rpn); + if (lmsg->ce_mask & MAC_INFO_ATTR_RSSI) + nl_dump(p, " signal level: %.2fdBm", nl_dect_rssi_to_dbm(mi->mi_rssi)); + if (lmsg->ce_mask & MAC_INFO_ATTR_FPC && mi->mi_fpc) { + nl_dect_llme_fpc2str(mi->mi_fpc, buf, sizeof(buf)); + nl_dump(p, "\n\tMAC layer capabilities: %s", buf); + } + if (lmsg->ce_mask & MAC_INFO_ATTR_EFPC && mi->mi_efpc) { + nl_dect_llme_efpc2str(mi->mi_efpc, buf, sizeof(buf)); + nl_dump(p, "\n\tExtended MAC layer capabilities: %s", buf); + } + if (lmsg->ce_mask & MAC_INFO_ATTR_EFPC2 && mi->mi_efpc2) { + nl_dect_llme_efpc22str(mi->mi_efpc2, buf, sizeof(buf)); + nl_dump(p, "\n\tExtended MAC layer capabilities 2: %s", buf); + } + if (lmsg->ce_mask & MAC_INFO_ATTR_HLC && mi->mi_hlc) { + nl_dect_llme_hlc2str(mi->mi_hlc, buf, sizeof(buf)); + nl_dump(p, "\n\tHigher layer capabilities: %s", buf); + } + if (lmsg->ce_mask & MAC_INFO_ATTR_EHLC && mi->mi_ehlc) { + nl_dect_llme_ehlc2str(mi->mi_ehlc, buf, sizeof(buf)); + nl_dump(p, "\n\tExtended higher layer capabilities: %s", buf); + } + if (lmsg->ce_mask & MAC_INFO_ATTR_EHLC2 && mi->mi_ehlc2) { + nl_dect_llme_ehlc22str(mi->mi_ehlc2, buf, sizeof(buf)); + nl_dump(p, "\n\tExtended higher layer capabilities 2: %s", buf); + } + nl_dump(p, "\n"); +} + + +static struct nla_policy nl_dect_mac_info_policy[DECTA_MAC_INFO_MAX + 1] = { + [DECTA_MAC_INFO_PARI] = { .type = NLA_NESTED }, + [DECTA_MAC_INFO_RPN] = { .type = NLA_U8 }, + [DECTA_MAC_INFO_RSSI] = { .type = NLA_U8 }, + [DECTA_MAC_INFO_SARI_LIST] = { .type = NLA_NESTED }, + [DECTA_MAC_INFO_FPC] = { .type = NLA_U32 }, + [DECTA_MAC_INFO_HLC] = { .type = NLA_U16 }, + [DECTA_MAC_INFO_EFPC] = { .type = NLA_U16 }, + [DECTA_MAC_INFO_EHLC] = { .type = NLA_U32 }, + [DECTA_MAC_INFO_EFPC2] = { .type = NLA_U16 }, + [DECTA_MAC_INFO_EHLC2] = { .type = NLA_U32 }, + [DECTA_MAC_INFO_MFN] = { .type = NLA_U32 }, +}; + +static int nl_dect_llme_mac_info_parse(struct nl_dect_llme_msg *lmsg, + struct nlattr *tb[]) +{ + struct nl_dect_ari pari; + int err; + + if (tb[DECTA_MAC_INFO_PARI] != NULL) { + err = nl_dect_parse_ari(&pari, tb[DECTA_MAC_INFO_PARI]); + if (err < 0) + return err; + nl_dect_llme_mac_info_set_pari(lmsg, &pari); + } + if (tb[DECTA_MAC_INFO_RPN] != NULL) + nl_dect_llme_mac_info_set_rpn(lmsg, nla_get_u8(tb[DECTA_MAC_INFO_RPN])); + if (tb[DECTA_MAC_INFO_RSSI] != NULL) + nl_dect_llme_mac_info_set_rssi(lmsg, nla_get_u8(tb[DECTA_MAC_INFO_RSSI])); + if (tb[DECTA_MAC_INFO_FPC] != NULL) + nl_dect_llme_mac_info_set_fpc(lmsg, nla_get_u32(tb[DECTA_MAC_INFO_FPC])); + if (tb[DECTA_MAC_INFO_HLC] != NULL) + nl_dect_llme_mac_info_set_hlc(lmsg, nla_get_u16(tb[DECTA_MAC_INFO_HLC])); + if (tb[DECTA_MAC_INFO_EFPC] != NULL) + nl_dect_llme_mac_info_set_efpc(lmsg, nla_get_u16(tb[DECTA_MAC_INFO_EFPC])); + if (tb[DECTA_MAC_INFO_EHLC] != NULL) + nl_dect_llme_mac_info_set_ehlc(lmsg, nla_get_u32(tb[DECTA_MAC_INFO_EHLC])); + if (tb[DECTA_MAC_INFO_EFPC2] != NULL) + nl_dect_llme_mac_info_set_efpc2(lmsg, nla_get_u16(tb[DECTA_MAC_INFO_EFPC2])); + if (tb[DECTA_MAC_INFO_EHLC2] != NULL) + nl_dect_llme_mac_info_set_ehlc2(lmsg, nla_get_u32(tb[DECTA_MAC_INFO_EHLC2])); + return 0; +} + +static int nl_dect_llme_mac_info_build(struct nl_msg *msg, + struct nl_dect_llme_msg *lmsg) +{ + struct nl_dect_llme_mac_info *mi = mac_info(lmsg); + int err; + + if (lmsg->ce_mask & MAC_INFO_ATTR_PARI) { + err = nl_dect_fill_ari(msg, &mi->mi_pari, DECTA_MAC_INFO_PARI); + if (err < 0) + return err; + } + if (lmsg->ce_mask & MAC_INFO_ATTR_RPN) + NLA_PUT_U8(msg, DECTA_MAC_INFO_RPN, mi->mi_rpn); + if (lmsg->ce_mask & MAC_INFO_ATTR_FPC) + NLA_PUT_U32(msg, DECTA_MAC_INFO_FPC, mi->mi_fpc); + if (lmsg->ce_mask & MAC_INFO_ATTR_HLC) + NLA_PUT_U16(msg, DECTA_MAC_INFO_HLC, mi->mi_hlc); + if (lmsg->ce_mask & MAC_INFO_ATTR_EFPC) + NLA_PUT_U16(msg, DECTA_MAC_INFO_EFPC, mi->mi_efpc); + if (lmsg->ce_mask & MAC_INFO_ATTR_EHLC) + NLA_PUT_U32(msg, DECTA_MAC_INFO_EHLC, mi->mi_ehlc); + if (lmsg->ce_mask & MAC_INFO_ATTR_EFPC2) + NLA_PUT_U16(msg, DECTA_MAC_INFO_EFPC2, mi->mi_efpc2); + if (lmsg->ce_mask & MAC_INFO_ATTR_EHLC2) + NLA_PUT_U32(msg, DECTA_MAC_INFO_EHLC2, mi->mi_ehlc2); + if (lmsg->ce_mask & MAC_INFO_ATTR_MFN) + NLA_PUT_U32(msg, DECTA_MAC_INFO_MFN, mi->mi_mfn); + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +static const struct nl_dect_llme_link { + int (*parse)(struct nl_dect_llme_msg *, struct nlattr *[]); + int (*build)(struct nl_msg *, struct nl_dect_llme_msg *); + void (*dump)(const struct nl_dect_llme_msg *, struct nl_dump_params *); + struct nla_policy *policy; + unsigned int maxtype; +} nl_dect_llme_dispatch[DECT_LLME_MAX + 1] = { + [DECT_LLME_SCAN] = { + .policy = nl_dect_mac_info_policy, + .maxtype = DECTA_MAC_INFO_MAX, + .parse = nl_dect_llme_mac_info_parse, + .build = nl_dect_llme_mac_info_build, + .dump = nl_dect_llme_mac_info_dump, + }, + [DECT_LLME_MAC_INFO] = { + .policy = nl_dect_mac_info_policy, + .maxtype = DECTA_MAC_INFO_MAX, + .parse = nl_dect_llme_mac_info_parse, + .build = nl_dect_llme_mac_info_build, + .dump = nl_dect_llme_mac_info_dump, + }, + [DECT_LLME_MAC_RFP_PRELOAD] = { + .policy = nl_dect_mac_info_policy, + .maxtype = DECTA_MAC_INFO_MAX, + .parse = nl_dect_llme_mac_info_parse, + .build = nl_dect_llme_mac_info_build, + .dump = nl_dect_llme_mac_info_dump, + }, +}; + +static void llme_msg_dump(struct nl_object *obj, struct nl_dump_params *p) +{ + struct nl_dect_llme_msg *lmsg = nl_object_priv(obj); + const struct nl_dect_llme_link *link; + char buf1[64], buf2[64]; + + nl_dect_llme_msgtype2str(lmsg->lm_type, buf1, sizeof(buf1)); + nl_dect_llme_op2str(lmsg->lm_op, buf2, sizeof(buf2)); + nl_dump(p, "%s-%s: ", buf1, buf2); + + link = &nl_dect_llme_dispatch[lmsg->lm_type]; + link->dump(lmsg, p); +} + +static struct nla_policy nl_dect_llme_policy[DECTA_LLME_MAX + 1] = { + [DECTA_LLME_OP] = { .type = NLA_U8 }, + [DECTA_LLME_TYPE] = { .type = NLA_U8 }, + [DECTA_LLME_DATA] = { .type = NLA_NESTED }, +}; + +static int llme_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *n, struct nl_parser_param *pp) +{ + const struct nl_dect_llme_link *link; + struct dectmsg *dm = nlmsg_data(n); + struct nlattr *tb[DECTA_LLME_MAX + 1]; + struct nl_dect_llme_msg *lmsg; + uint8_t op, type; + int err; + + err = nlmsg_parse(n, sizeof(*dm), tb, DECTA_LLME_MAX, nl_dect_llme_policy); + if (err < 0) + return err; + + if (tb[DECTA_LLME_OP] == NULL || + tb[DECTA_LLME_TYPE] == NULL || + tb[DECTA_LLME_DATA] == NULL) + return -NLE_INVAL; + + type = nla_get_u8(tb[DECTA_LLME_TYPE]); + if (type > DECT_LLME_MAX) + return -NLE_INVAL; + link = &nl_dect_llme_dispatch[type]; + + op = nla_get_u8(tb[DECTA_LLME_OP]); + switch (op) { + case DECT_LLME_REQUEST: + case DECT_LLME_INDICATE: + case DECT_LLME_RESPONSE: + case DECT_LLME_CONFIRM: + if (link->parse == NULL) + return -NLE_OPNOTSUPP; + break; + default: + return -NLE_INVAL; + } + + lmsg = nl_dect_llme_msg_alloc(); + lmsg->ce_msgtype = n->nlmsg_type; + lmsg->lm_index = dm->dm_index; + + nl_dect_llme_msg_set_type(lmsg, type); + nl_dect_llme_msg_set_op(lmsg, op); + + if (1) { + struct nlattr *nla[link->maxtype + 1]; + + err = nla_parse_nested(nla, link->maxtype, tb[DECTA_LLME_DATA], + link->policy); + if (err < 0) + goto errout; + err = link->parse(lmsg, nla); + if (err < 0) + goto errout; + } + + err = pp->pp_cb((struct nl_object *)lmsg, pp); +errout: + nl_dect_llme_msg_put(lmsg); + return err; +} + +/** + * @name message creation + * @{ + */ + +static int nl_dect_llme_build_msg(struct nl_msg *msg, struct nl_dect_llme_msg *lmsg, + enum dect_llme_ops op) +{ + const struct nl_dect_llme_link *link; + struct nlattr *nest; + struct dectmsg dm = { + .dm_index = lmsg->lm_index, + }; + + if (nlmsg_append(msg, &dm, sizeof(dm), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + NLA_PUT_U8(msg, DECTA_LLME_OP, op); + NLA_PUT_U8(msg, DECTA_LLME_TYPE, lmsg->lm_type); + + link = &nl_dect_llme_dispatch[lmsg->lm_type]; + nest = nla_nest_start(msg, DECTA_LLME_DATA); + if (nest == NULL) + goto nla_put_failure; + if (link->build(msg, lmsg) < 0) + goto nla_put_failure; + nla_nest_end(msg, nest); + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +static int build_llme_msg(struct nl_dect_llme_msg *tmpl, enum dect_llme_ops op, + struct nl_msg **result) +{ + struct nl_msg *msg; + int err; + + if (!(msg = nlmsg_alloc_simple(DECT_LLME_MSG, 0))) + return -NLE_NOMEM; + + if ((err = nl_dect_llme_build_msg(msg, tmpl, op)) < 0) { + nlmsg_free(msg); + return err; + } + + *result = msg; + return 0; +} + +int nl_dect_llme_build_request(struct nl_dect_llme_msg *tmpl, + struct nl_msg **result) +{ + return build_llme_msg(tmpl, DECT_LLME_REQUEST, result); +} + +int nl_dect_llme_request(struct nl_sock *sk, struct nl_dect_llme_msg *lmsg) +{ + struct nl_msg *msg; + int err; + + if ((err = nl_dect_llme_build_request(lmsg, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +int nl_dect_llme_build_response(struct nl_dect_llme_msg *tmpl, + struct nl_msg **result) +{ + return build_llme_msg(tmpl, DECT_LLME_RESPONSE, result); +} + +int nl_dect_llme_respond(struct nl_sock *sk, struct nl_dect_llme_msg *tmpl) +{ + struct nl_msg *msg; + int err; + + if ((err = nl_dect_llme_build_response(tmpl, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +void nl_dect_llme_msg_set_index(struct nl_dect_llme_msg *lmsg, int index) +{ + lmsg->lm_index = index; +} + +void nl_dect_llme_msg_set_type(struct nl_dect_llme_msg *lmsg, + enum dect_llme_msg_types type) +{ + lmsg->lm_type = type; +} + +enum dect_llme_msg_types nl_dect_llme_msg_get_type(const struct nl_dect_llme_msg *lmsg) +{ + return lmsg->lm_type; +} + +enum dect_llme_ops nl_dect_llme_msg_get_op(const struct nl_dect_llme_msg *lmsg) +{ + return lmsg->lm_op; +} + +void nl_dect_llme_msg_set_op(struct nl_dect_llme_msg *lmsg, enum dect_llme_ops op) +{ + lmsg->lm_op = op; +} + +/** @} */ + +/** + * @name Allocation/Freeing + * @{ + */ + +struct nl_dect_llme_msg *nl_dect_llme_msg_alloc(void) +{ + return (struct nl_dect_llme_msg *)nl_object_alloc(&llme_msg_obj_ops); +} + +void nl_dect_llme_msg_get(struct nl_dect_llme_msg *lmsg) +{ + nl_object_get((struct nl_object *)lmsg); +} + +void nl_dect_llme_msg_put(struct nl_dect_llme_msg *lmsg) +{ + nl_object_put((struct nl_object *)lmsg); +} + +/** @} */ + +static struct trans_tbl llme_types[] = { + __ADD(DECT_LLME_SCAN, SCAN) + __ADD(DECT_LLME_MAC_INFO, MAC_INFO) +}; + +char *nl_dect_llme_msgtype2str(enum dect_llme_msg_types type, char *buf, size_t len) +{ + return __type2str(type, buf, len, llme_types, ARRAY_SIZE(llme_types)); +} + +enum dect_llme_msg_types nl_dect_llme_str2msgtype(const char *str) +{ + return __str2type(str, llme_types, ARRAY_SIZE(llme_types)); +} + +static struct trans_tbl llme_ops[] = { + __ADD(DECT_LLME_REQUEST, req) + __ADD(DECT_LLME_INDICATE, ind) + __ADD(DECT_LLME_RESPONSE, res) + __ADD(DECT_LLME_CONFIRM, cfm) +}; + +char *nl_dect_llme_op2str(enum dect_llme_ops op, char *buf, size_t len) +{ + return __type2str(op, buf, len, llme_ops, ARRAY_SIZE(llme_ops)); +} + +enum dect_llme_ops nl_dect_llme_str2op(const char *str) +{ + return __str2type(str, llme_ops, ARRAY_SIZE(llme_ops)); +} + +/** @cond SKIP */ +static struct nl_object_ops llme_msg_obj_ops = { + .oo_name = "nl_dect/llme_msg", + .oo_size = sizeof(struct nl_dect_llme_msg), + .oo_dump = { + [NL_DUMP_LINE] = llme_msg_dump, + }, +}; + +static struct nl_cache_ops nl_dect_llme_msg_ops = { + .co_name = "nl_dect/llme_msg", + .co_protocol = NETLINK_DECT, + .co_msgtypes = { + { DECT_LLME_MSG, NL_ACT_NEW, "new" }, + END_OF_MSGTYPES_LIST, + }, + .co_msg_parser = llme_msg_parser, + .co_obj_ops = &llme_msg_obj_ops, +}; +/** @endcond */ + +static void __init llme_init(void) +{ + nl_cache_mngt_register(&nl_dect_llme_msg_ops); +} + +static void __exit llme_exit(void) +{ + nl_cache_mngt_unregister(&nl_dect_llme_msg_ops); +} + +/** @} */ diff --git a/lib/dect/transceiver.c b/lib/dect/transceiver.c new file mode 100644 index 0000000..330fbd4 --- /dev/null +++ b/lib/dect/transceiver.c @@ -0,0 +1,307 @@ +/* + * lib/dect/transceiver.c DECT Transceiver objects + * + * 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 version 2.1 + * of the License. + * + * Copyright (c) 2009 Patrick McHardy <kaber@trash.net> + */ + +/** + * @ingroup dect + * @defgroup dect Transceivers + * @brief + * @{ + */ + +#include <netlink-private/netlink.h> +#include <netlink/netlink.h> +#include <netlink/utils.h> +#include <netlink/dect/transceiver.h> + +/** @cond SKIP */ +static struct nl_cache_ops nl_dect_transceiver_ops; +/** @endcond */ + +#define DECTNAMSIZ 16 + +static struct nla_policy transceiver_policy[DECTA_TRANSCEIVER_MAX + 1] = { + [DECTA_TRANSCEIVER_NAME] = { .type = NLA_STRING, .maxlen = DECTNAMSIZ }, + [DECTA_TRANSCEIVER_TYPE] = { .type = NLA_STRING }, + [DECTA_TRANSCEIVER_FEATURES] = { .type = NLA_U32 }, + [DECTA_TRANSCEIVER_LINK] = { .type = NLA_U8 }, + [DECTA_TRANSCEIVER_STATS] = { .type = NLA_NESTED }, + [DECTA_TRANSCEIVER_BAND] = { .type = NLA_U8 }, + [DECTA_TRANSCEIVER_SLOTS] = { .type = NLA_NESTED }, +}; + +static struct nla_policy stats_policy[DECTA_TRANSCEIVER_STATS_MAX + 1] = { + [DECTA_TRANSCEIVER_STATS_EVENT_BUSY] = { .type = NLA_U32 }, + [DECTA_TRANSCEIVER_STATS_EVENT_LATE] = { .type = NLA_U32 }, +}; + +static struct nla_policy slot_policy[DECTA_SLOT_MAX + 1] = { + [DECTA_SLOT_NUM] = { .type = NLA_U8 }, + [DECTA_SLOT_STATE] = { .type = NLA_U8 }, + [DECTA_SLOT_FLAGS] = { .type = NLA_U32 }, + [DECTA_SLOT_PACKET] = { .type = NLA_U8 }, + [DECTA_SLOT_CARRIER] = { .type = NLA_U8 }, + [DECTA_SLOT_FREQUENCY] = { .type = NLA_U32 }, + [DECTA_SLOT_PHASEOFF] = { .type = NLA_U32 }, + [DECTA_SLOT_RSSI] = { .type = NLA_U8 }, + [DECTA_SLOT_RX_BYTES] = { .type = NLA_U32 }, + [DECTA_SLOT_RX_PACKETS] = { .type = NLA_U32 }, + [DECTA_SLOT_RX_A_CRC_ERRORS] = { .type = NLA_U32 }, + [DECTA_SLOT_RX_X_CRC_ERRORS] = { .type = NLA_U32 }, + [DECTA_SLOT_RX_Z_CRC_ERRORS] = { .type = NLA_U32 }, + [DECTA_SLOT_TX_BYTES] = { .type = NLA_U32 }, + [DECTA_SLOT_TX_PACKETS] = { .type = NLA_U32 }, +}; + +static int slot_parser(struct nl_dect_transceiver *trx, struct nlattr *nla) +{ + struct nlattr *tb[DECTA_SLOT_MAX + 1]; + struct nl_dect_transceiver_slot *dts; + uint8_t slot; + int err; + + err = nla_parse_nested(tb, DECTA_SLOT_MAX, nla, slot_policy); + if (err < 0) + return err; + + if (tb[DECTA_SLOT_NUM] == NULL) + return -NLE_INVAL; + slot = nla_get_u8(tb[DECTA_SLOT_NUM]); + dts = &trx->trx_slots[slot]; + + dts->dts_valid = 1; + if (tb[DECTA_SLOT_STATE] != NULL) + dts->dts_state = nla_get_u8(tb[DECTA_SLOT_STATE]); + if (tb[DECTA_SLOT_FLAGS] != NULL) + dts->dts_flags = nla_get_u32(tb[DECTA_SLOT_FLAGS]); + if (tb[DECTA_SLOT_PACKET] != NULL) + dts->dts_packet = nla_get_u8(tb[DECTA_SLOT_PACKET]); + if (tb[DECTA_SLOT_CARRIER] != NULL) + dts->dts_carrier = nla_get_u8(tb[DECTA_SLOT_CARRIER]); + if (tb[DECTA_SLOT_FREQUENCY] != NULL) + dts->dts_frequency = nla_get_u32(tb[DECTA_SLOT_FREQUENCY]); + if (tb[DECTA_SLOT_PHASEOFF] != NULL) + dts->dts_phaseoff = nla_get_u32(tb[DECTA_SLOT_PHASEOFF]); + if (tb[DECTA_SLOT_RSSI] != NULL) + dts->dts_rssi = nla_get_u8(tb[DECTA_SLOT_RSSI]); + if (tb[DECTA_SLOT_RX_BYTES] != NULL) + dts->dts_rx_bytes = nla_get_u32(tb[DECTA_SLOT_RX_BYTES]); + if (tb[DECTA_SLOT_RX_PACKETS] != NULL) + dts->dts_rx_packets = nla_get_u32(tb[DECTA_SLOT_RX_PACKETS]); + if (tb[DECTA_SLOT_RX_A_CRC_ERRORS] != NULL) + dts->dts_rx_a_crc_errors = nla_get_u32(tb[DECTA_SLOT_RX_A_CRC_ERRORS]); + if (tb[DECTA_SLOT_RX_X_CRC_ERRORS] != NULL) + dts->dts_rx_x_crc_errors = nla_get_u32(tb[DECTA_SLOT_RX_X_CRC_ERRORS]); + if (tb[DECTA_SLOT_RX_Z_CRC_ERRORS] != NULL) + dts->dts_rx_z_crc_errors = nla_get_u32(tb[DECTA_SLOT_RX_Z_CRC_ERRORS]); + if (tb[DECTA_SLOT_TX_BYTES] != NULL) + dts->dts_tx_bytes = nla_get_u32(tb[DECTA_SLOT_TX_BYTES]); + if (tb[DECTA_SLOT_TX_PACKETS] != NULL) + dts->dts_tx_packets = nla_get_u32(tb[DECTA_SLOT_TX_PACKETS]); + return 0; +} + +static int stats_parser(struct nl_dect_transceiver *trx, struct nlattr *nla) +{ + struct nlattr *tb[DECTA_TRANSCEIVER_STATS_MAX + 1]; + struct nl_dect_transceiver_stats *stats = &trx->trx_stats; + int err; + + err = nla_parse_nested(tb, DECTA_TRANSCEIVER_STATS_MAX, nla, stats_policy); + if (err < 0) + return err; + + if (tb[DECTA_TRANSCEIVER_STATS_EVENT_BUSY] != NULL) + stats->trx_event_busy = + nla_get_u32(tb[DECTA_TRANSCEIVER_STATS_EVENT_BUSY]); + if (tb[DECTA_TRANSCEIVER_STATS_EVENT_LATE] != NULL) + stats->trx_event_late = + nla_get_u32(tb[DECTA_TRANSCEIVER_STATS_EVENT_LATE]); + return 0; +} + +static int transceiver_msg_parser(struct nl_cache_ops *ops, + struct sockaddr_nl *who, + struct nlmsghdr *n, + struct nl_parser_param *pp) +{ + struct nlattr *tb[DECTA_TRANSCEIVER_MAX + 1], *nla; + struct nl_dect_transceiver *trx; + int err; + + trx = nl_dect_transceiver_alloc(); + if (trx == NULL) { + err = -NLE_NOMEM; + goto errout; + } + + trx->ce_msgtype = n->nlmsg_type; + + err = nlmsg_parse(n, sizeof(struct dectmsg), tb, DECTA_TRANSCEIVER_MAX, + transceiver_policy); + if (err < 0) + goto errout; + + if (tb[DECTA_TRANSCEIVER_NAME] != NULL) { + char name[DECTNAMSIZ]; + nla_strlcpy(name, tb[DECTA_TRANSCEIVER_NAME], sizeof(name)); + nl_dect_transceiver_set_name(trx, name); + } + + if (tb[DECTA_TRANSCEIVER_TYPE] != NULL) { + char *type = nla_strdup(tb[DECTA_TRANSCEIVER_TYPE]); + if (type == NULL) { + err = -NLE_NOMEM; + goto errout; + } + nl_dect_transceiver_set_type(trx, type); + free(type); + } + + if (tb[DECTA_TRANSCEIVER_FEATURES] != NULL) + nl_dect_transceiver_set_features(trx, nla_get_u32(tb[DECTA_TRANSCEIVER_FEATURES])); + + if (tb[DECTA_TRANSCEIVER_LINK] != NULL) + nl_dect_transceiver_set_link(trx, nla_get_u8(tb[DECTA_TRANSCEIVER_LINK])); + + if (tb[DECTA_TRANSCEIVER_STATS] != NULL) { + err = stats_parser(trx, tb[DECTA_TRANSCEIVER_STATS]); + if (err < 0) + goto errout; + } + + if (tb[DECTA_TRANSCEIVER_BAND] != NULL) + nl_dect_transceiver_set_band(trx, nla_get_u8(tb[DECTA_TRANSCEIVER_BAND])); + + if (tb[DECTA_TRANSCEIVER_SLOTS] != NULL) { + int rem; + nla_for_each_nested(nla, tb[DECTA_TRANSCEIVER_SLOTS], rem) { + if (nla_type(nla) != DECTA_LIST_ELEM) + continue; + err = slot_parser(trx, nla); + if (err < 0) + goto errout; + } + } + + err = pp->pp_cb((struct nl_object *)trx, pp); +errout: + nl_dect_transceiver_put(trx); + return err; +} + +static int transceiver_request_update(struct nl_cache *c, struct nl_sock *h) +{ + struct dectmsg dm; + + memset(&dm, 0, sizeof(dm)); + return nl_send_simple(h, DECT_GET_TRANSCEIVER, NLM_F_DUMP, + &dm, sizeof(dm)); +} + +/** + * @name Cache Management + * @{ + */ +int nl_dect_transceiver_alloc_cache(struct nl_sock *sk, struct nl_cache **result) +{ + struct nl_cache *cache; + int err; + + cache = nl_cache_alloc(&nl_dect_transceiver_ops); + if (cache == NULL) + return -NLE_NOMEM; + + if (sk && (err = nl_cache_refill(sk, cache)) < 0) { + free(cache); + return err; + } + + *result = cache; + return 0; +} + +/** @} */ + +/** + * @name Transceiver creation + * @{ + */ + +static int build_transceiver_msg(struct nl_dect_transceiver *tmpl, int cmd, + int flags, struct nl_msg **result) +{ + struct nl_msg *msg; + int err; + + msg = nlmsg_alloc_simple(cmd, flags); + if (msg == NULL) + return -NLE_NOMEM; + + err = nl_dect_transceiver_build_msg(msg, tmpl); + if (err < 0) { + nlmsg_free(msg); + return err; + } + + *result = msg; + return 0; +} + +int nl_dect_transceiver_build_change_request(struct nl_dect_transceiver *tmpl, + int flags, struct nl_msg **result) +{ + return build_transceiver_msg(tmpl, DECT_NEW_TRANSCEIVER, flags, result); +} + +int nl_dect_transceiver_change(struct nl_sock *sk, struct nl_dect_transceiver *trx, + int flags) +{ + struct nl_msg *msg; + int err; + + err = nl_dect_transceiver_build_change_request(trx, flags, &msg); + if (err < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +static struct nl_cache_ops nl_dect_transceiver_ops = { + .co_name = "nl_dect/transceiver", + .co_hdrsize = 0, + .co_msgtypes = { + { DECT_NEW_TRANSCEIVER, NL_ACT_NEW, "new" }, + { DECT_GET_TRANSCEIVER, NL_ACT_GET, "get" }, + { DECT_DEL_TRANSCEIVER, NL_ACT_DEL, "del" }, + END_OF_MSGTYPES_LIST + }, + .co_protocol = NETLINK_DECT, + .co_request_update = transceiver_request_update, + .co_msg_parser = transceiver_msg_parser, + .co_obj_ops = &nl_dect_transceiver_obj_ops, +}; + +static void __init transceiver_init(void) +{ + nl_cache_mngt_register(&nl_dect_transceiver_ops); +} + +static void __exit transceiver_exit(void) +{ + nl_cache_mngt_unregister(&nl_dect_transceiver_ops); +} + +/** @} */ diff --git a/lib/dect/transceiver_obj.c b/lib/dect/transceiver_obj.c new file mode 100644 index 0000000..1638471 --- /dev/null +++ b/lib/dect/transceiver_obj.c @@ -0,0 +1,335 @@ +/* + * lib/dect/transceiver_obj.c DECT Transceiver objects + * + * 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 version 2.1 + * of the License. + * + * Copyright (c) 2009 Patrick McHardy <kaber@trash.net> + */ + +#include <netlink-private/netlink.h> +#include <netlink/netlink.h> +#include <netlink/cache.h> +#include <netlink/utils.h> +#include <netlink/data.h> +#include <netlink/dect/dect.h> +#include <netlink/dect/cell.h> +#include <netlink/dect/transceiver.h> + +/** @cond SKIP */ +#define TRANSCEIVER_ATTR_NAME 0x0001 +#define TRANSCEIVER_ATTR_TYPE 0x0002 +#define TRANSCEIVER_ATTR_FEATURES 0x0004 +#define TRANSCEIVER_ATTR_INDEX 0x0008 +#define TRANSCEIVER_ATTR_LINK 0x0010 +#define TRANSCEIVER_ATTR_BAND 0x0020 +/** @endtsond */ + +static void transceiver_free_data(struct nl_object *obj) +{ + struct nl_dect_transceiver *trx = nl_object_priv(obj); + + if (trx == NULL) + return; + free(trx->trx_name); + free(trx->trx_type); +} + +static void slot_dump(struct nl_dect_transceiver_slot *dts, unsigned int n, + struct nl_dump_params *p) +{ + int64_t offset; + char buf[64]; + + nl_dect_slot_state2str(dts->dts_state, buf, sizeof(buf)); + nl_dump(p, "\tslot %u: <%s", n, buf); + if (dts->dts_flags) { + nl_dect_slot_flags2str(dts->dts_flags, buf, sizeof(buf)); + nl_dump(p, ",%s", buf); + } + nl_dump(p, "> "); + + if (dts->dts_state != DECT_SLOT_IDLE) { + nl_dump(p, "packet: %s ", + nl_dect_slot_packet2str(dts->dts_packet, buf, + sizeof(buf))); + + nl_dump(p, "carrier: %u (%u.%03u MHz", dts->dts_carrier, + dts->dts_frequency / 1000, dts->dts_frequency % 1000); + + if (dts->dts_state == DECT_SLOT_RX) { + offset = (int64_t)dts->dts_frequency * + dts->dts_phaseoff / + DECT_PHASE_OFFSET_SCALE; + nl_dump(p, " %+" PRId64 ".%03" PRIu64 " kHz", + offset / 1000000, + llabs(offset) % 1000000 / 1000); + } + nl_dump(p, ")"); + } + + if (dts->dts_state == DECT_SLOT_RX) + nl_dump(p, " signal level: %.2fdBm", + nl_dect_rssi_to_dbm(dts->dts_rssi)); + nl_dump(p, "\n"); + + nl_dump(p, "\t RX: bytes %u packets %u a-crc-errors %u " + "x-crc-errors %u z-crc-errors %u\n", + dts->dts_rx_bytes, dts->dts_rx_packets, + dts->dts_rx_a_crc_errors, + dts->dts_rx_x_crc_errors, + dts->dts_rx_z_crc_errors); + nl_dump(p, "\t TX: bytes %u packets %u\n", + dts->dts_tx_bytes, dts->dts_tx_packets); +} + +static void transceiver_dump(struct nl_object *obj, struct nl_dump_params *p) +{ + struct nl_dect_transceiver *trx = nl_object_priv(obj); + struct nl_dect_transceiver_stats *stats = &trx->trx_stats; + struct nl_dect_transceiver_slot *dts; + struct nl_cache *cell_cache; + char buf[64]; + unsigned int n; + + nl_dump(p, "DECT Transceiver "); + if (trx->trx_name != NULL) + nl_dump_line(p, "%s", trx->trx_name); + + if (trx->trx_link) { + cell_cache = nl_cache_mngt_require("nl_dect/cell"); + if (cell_cache != NULL) { + nl_dump(p, "@%s", + nl_dect_cell_i2name(cell_cache, trx->trx_link, + buf, sizeof(buf))); + } else + nl_dump(p, "@%d", trx->trx_link); + } + nl_dump(p, ":\n"); + if (trx->trx_type != NULL) + nl_dump_line(p, "\tType: %s\n", trx->trx_type); + if (trx->trx_features != 0) + nl_dump_line(p, "\tFeatures: %s\n", + nl_dect_transceiver_features2str(trx->trx_features, + buf, sizeof(buf))); + nl_dump(p, "\tRF-band: %.5u\n", trx->trx_band); + nl_dump(p, "\tEvents: busy: %u late: %u\n", + stats->trx_event_busy, stats->trx_event_late); + + nl_dump(p, "\n"); + for (n = 0; n < 24; n++) { + dts = &trx->trx_slots[n]; + if (!dts->dts_valid) + continue; + slot_dump(dts, n, p); + } +} + +static int nl_dect_transceiver_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct nl_dect_transceiver *a = (struct nl_dect_transceiver *)_a; + struct nl_dect_transceiver *b = (struct nl_dect_transceiver *)_b; + int diff = 0; + +#define TRX_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TRANSCEIVER_ATTR_##ATTR, a, b, EXPR) + + diff |= TRX_DIFF(NAME, strcmp(a->trx_name, b->trx_name)); + diff |= TRX_DIFF(LINK, a->trx_link != b->trx_link); + +#undef TRX_DIFF + + return diff; +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct nl_dect_transceiver *nl_dect_transceiver_alloc(void) +{ + return (struct nl_dect_transceiver *)nl_object_alloc(&nl_dect_transceiver_obj_ops); +} + +void nl_dect_transceiver_get(struct nl_dect_transceiver *trx) +{ + nl_object_get((struct nl_object *)trx); +} + +void nl_dect_transceiver_put(struct nl_dect_transceiver *trx) +{ + nl_object_put((struct nl_object *)trx); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void nl_dect_transceiver_set_name(struct nl_dect_transceiver *trx, const char *name) +{ + trx->trx_name = strdup(name); + trx->ce_mask |= TRANSCEIVER_ATTR_NAME; +} + +bool nl_dect_transceiver_test_name(const struct nl_dect_transceiver *trx) +{ + return !!(trx->ce_mask & TRANSCEIVER_ATTR_NAME); +} + +const char *nl_dect_transceiver_get_name(const struct nl_dect_transceiver *trx) +{ + return trx->trx_name; +} + +void nl_dect_transceiver_set_type(struct nl_dect_transceiver *trx, const char *type) +{ + trx->trx_type = strdup(type); + trx->ce_mask |= TRANSCEIVER_ATTR_TYPE; +} + +bool nl_dect_transceiver_test_type(const struct nl_dect_transceiver *trx) +{ + return !!(trx->ce_mask & TRANSCEIVER_ATTR_TYPE); +} + +const char *nl_dect_transceiver_get_type(const struct nl_dect_transceiver *trx) +{ + return trx->trx_type; +} + +void nl_dect_transceiver_set_features(struct nl_dect_transceiver *trx, uint32_t features) +{ + trx->trx_features = features; + trx->ce_mask |= TRANSCEIVER_ATTR_FEATURES; +} + +void nl_dect_transceiver_set_index(struct nl_dect_transceiver *trx, int index) +{ + trx->trx_index = index; + trx->ce_mask |= TRANSCEIVER_ATTR_INDEX; +} + +void nl_dect_transceiver_set_link(struct nl_dect_transceiver *trx, uint8_t link) +{ + trx->trx_link = link; + trx->ce_mask |= TRANSCEIVER_ATTR_LINK; +} + +void nl_dect_transceiver_set_band(struct nl_dect_transceiver *trx, uint8_t band) +{ + trx->trx_band = band; + trx->ce_mask |= TRANSCEIVER_ATTR_BAND; +} + +bool nl_dect_transceiver_test_band(const struct nl_dect_transceiver *trx) +{ + return !!(trx->ce_mask & TRANSCEIVER_ATTR_BAND); +} + +uint8_t nl_dect_transceiver_get_band(const struct nl_dect_transceiver *trx) +{ + return trx->trx_band; +} + +static struct trans_tbl trx_features[] = { + __ADD(DECT_TRANSCEIVER_SLOW_HOPPING, slow-hopping) + __ADD(DECT_TRANSCEIVER_PACKET_P64, p64) +}; + +const char *nl_dect_transceiver_features2str(uint32_t features, char *buf, size_t len) +{ + return __flags2str(features, buf, len, trx_features, + ARRAY_SIZE(trx_features)); +} + +static struct trans_tbl slot_states[] = { + __ADD(DECT_SLOT_IDLE, idle) + __ADD(DECT_SLOT_SCANNING, scanning) + __ADD(DECT_SLOT_RX, rx) + __ADD(DECT_SLOT_TX, tx) +}; + +const char *nl_dect_slot_state2str(uint8_t state, char *buf, size_t len) +{ + return __type2str(state, buf, len, slot_states, + ARRAY_SIZE(slot_states)); +} + +uint8_t nl_dect_slot_str2state(const char *str) +{ + return __str2type(str, slot_states, ARRAY_SIZE(slot_states)); +} + +static struct trans_tbl slot_flags[] = { + __ADD(DECT_SLOT_SYNC, sync) + __ADD(DECT_SLOT_CIPHER, cipher) +}; + +const char *nl_dect_slot_flags2str(uint32_t state, char *buf, size_t len) +{ + return __flags2str(state, buf, len, slot_flags, ARRAY_SIZE(slot_flags)); +} + +uint32_t nl_dect_slot_str2flags(const char *str) +{ + return __str2flags(str, slot_flags, ARRAY_SIZE(slot_flags)); +} + +static struct trans_tbl packet_types[] = { + __ADD(DECT_PACKET_P00, P00) + __ADD(DECT_PACKET_P08, P08) + __ADD(DECT_PACKET_P32, P32) + __ADD(DECT_PACKET_P80, P80) + __ADD(DECT_PACKET_P640j, P640j) + __ADD(DECT_PACKET_P640j, P672j) +}; + +const char *nl_dect_slot_packet2str(uint8_t pkt, char *buf, size_t len) +{ + return __type2str(pkt, buf, len, packet_types, ARRAY_SIZE(packet_types)); +} + +uint8_t nl_dect_slot_str2packet(const char *str) +{ + return __str2type(str, packet_types, ARRAY_SIZE(packet_types)); +} + +int nl_dect_transceiver_build_msg(struct nl_msg *msg, struct nl_dect_transceiver *trx) +{ + struct dectmsg dm = { + .dm_index = trx->trx_index, + }; + + if (nlmsg_append(msg, &dm, sizeof(dm), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + if (trx->ce_mask & TRANSCEIVER_ATTR_NAME) + NLA_PUT_STRING(msg, DECTA_TRANSCEIVER_NAME, trx->trx_name); + if (trx->ce_mask & TRANSCEIVER_ATTR_LINK) + NLA_PUT_U8(msg, DECTA_TRANSCEIVER_LINK, trx->trx_link); + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +/** @cond SKIP */ +struct nl_object_ops nl_dect_transceiver_obj_ops = { + .oo_name = "nl_dect/transceiver", + .oo_size = sizeof(struct nl_dect_transceiver), + .oo_free_data = transceiver_free_data, + .oo_dump = { + [NL_DUMP_LINE] = transceiver_dump, + }, + .oo_compare = nl_dect_transceiver_compare, + .oo_id_attrs = TRANSCEIVER_ATTR_NAME, +}; + +/** @endcond */ + +/** @} */ diff --git a/libnl-dect-3.0.pc.in b/libnl-dect-3.0.pc.in new file mode 100644 index 0000000..5bab3bf --- /dev/null +++ b/libnl-dect-3.0.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libnl-dect +Description: DECT Netlink Library +Version: @PACKAGE_VERSION@ +Requires: libnl-3.0 +Libs: -L${libdir} -lnl-dect-@MAJ_VERSION@ +Cflags: -I${includedir}/libnl@MAJ_VERSION@ diff --git a/src/.gitignore b/src/.gitignore index 3e091cb..1624901 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -38,6 +38,15 @@ nl-rule-list nl-tctree-list nl-util-addr nf-queue +dect-transceiver-list +dect-transceiver-bind +dect-cell-add +dect-cell-delete +dect-cell-list +dect-cluster-add +dect-cluster-delete +dect-cluster-list +dect-llme-scan nl-classid-lookup nl-pktloc-lookup nl-link-enslave diff --git a/src/Makefile.am b/src/Makefile.am index c318dcc..aa6ffe7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,7 +9,8 @@ LDADD = \ ${top_builddir}/lib/libnl-3.la \ ${top_builddir}/lib/libnl-nf-3.la \ ${top_builddir}/lib/libnl-genl-3.la \ - ${top_builddir}/lib/libnl-route-3.la + ${top_builddir}/lib/libnl-route-3.la \ + $(top_builddir)/lib/libnl-dect-3.la sbin_PROGRAMS = \ genl-ctrl-list \ @@ -36,7 +37,11 @@ noinst_PROGRAMS = \ nl-list-caches nl-list-sockets \ nl-util-addr \ nl-link-enslave \ - nl-link-release + nl-link-release \ + dect-transceiver-bind dect-transceiver-list \ + dect-cell-add dect-cell-delete dect-cell-list \ + dect-cluster-add dect-cluster-delete dect-cluster-list \ + dect-llme-monitor dect-llme-scan genl_ctrl_list_SOURCES = genl-ctrl-list.c @@ -96,5 +101,20 @@ nl_list_sockets_SOURCES = nl-list-sockets.c nl_util_addr_SOURCES = nl-util-addr.c nl_pktloc_lookup_SOURCES = nl-pktloc-lookup.c +nl_pktloc_lookup_LDADD = -lnl-route nl_classid_lookup_SOURCES = nl-classid-lookup.c + +dect_transceiver_bind_SOURCES = dect-transceiver-bind.c +dect_transceiver_list_SOURCES = dect-transceiver-list.c + +dect_cell_add_SOURCES = dect-cell-add.c +dect_cell_delete_SOURCES = dect-cell-delete.c +dect_cell_list_SOURCES = dect-cell-list.c + +dect_cluster_add_SOURCES = dect-cluster-add.c +dect_cluster_delete_SOURCES = dect-cluster-delete.c +dect_cluster_list_SOURCES = dect-cluster-list.c + +dect_llme_monitor_SOURCES = dect-llme-monitor.c +dect_llme_scan_SOURCES = dect-llme-scan.c diff --git a/src/dect-cell-add.c b/src/dect-cell-add.c new file mode 100644 index 0000000..f9448a0 --- /dev/null +++ b/src/dect-cell-add.c @@ -0,0 +1,67 @@ +#include "netlink/cli/utils.h" + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_dect_cell *cell; + struct nl_cache *cluster_cache; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + uint8_t cli; + int err; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_DECT); + + if (nl_dect_cluster_alloc_cache(sock, &cluster_cache)) + exit(1); + nl_cache_mngt_provide(cluster_cache); + + cell = nl_dect_cell_alloc(); + for (;;) { + int c, optidx = 0; + enum { + ARG_NAME = 256, + ARG_FLAGS, + ARG_CLUSTER, + }; + static struct option long_opts[] = { + { "name", 1, 0, ARG_NAME }, + { "flags", 1, 0, ARG_FLAGS }, + { "cluster", 1, 0, ARG_CLUSTER }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "qhvd:n:t:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'v': nl_cli_print_version(); break; + case ARG_NAME: + nl_dect_cell_set_name(cell, optarg); + break; + case ARG_FLAGS: + nl_dect_cell_set_flags(cell, nl_dect_cell_str2flags(optarg)); + break; + case ARG_CLUSTER: + if (isdigit(*optarg)) + cli = strtoul(optarg, NULL, 0); + else + cli = nl_dect_cluster_name2i(cluster_cache, optarg); + nl_dect_cell_set_link(cell, cli); + break; + } + } + + err = nl_dect_cell_add(sock, cell, 0); + if (err < 0) + nl_cli_fatal(err, "Unable to add cell: %s", nl_geterror(err)); + + printf("Added: "); + nl_object_dump(OBJ_CAST(cell), ¶ms); + return 0; +} + diff --git a/src/dect-cell-delete.c b/src/dect-cell-delete.c new file mode 100644 index 0000000..2cb2747 --- /dev/null +++ b/src/dect-cell-delete.c @@ -0,0 +1,59 @@ +#include "netlink/cli/utils.h" + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_dect_cell *cell; + struct nl_cache *cluster_cache; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int err; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_DECT); + + if (nl_dect_cluster_alloc_cache(sock, &cluster_cache)) + exit(1); + nl_cache_mngt_provide(cluster_cache); + + cell = nl_dect_cell_alloc(); + for (;;) { + int c, optidx = 0; + enum { + ARG_CELL = 257, + ARG_CLUSTER, + ARG_TRANSCEIVER, + }; + static struct option long_opts[] = { + { "cell", 1, 0, ARG_CELL }, + { "cluster", 1, 0, ARG_CLUSTER }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "qhvd:n:t:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'v': nl_cli_print_version(); break; + case ARG_CELL: + nl_dect_cell_set_name(cell, optarg); + break; + case ARG_CLUSTER: + nl_dect_cell_set_link(cell, + nl_dect_cluster_name2i(cluster_cache, optarg)); + break; + } + } + + err = nl_dect_cell_delete(sock, cell, 0); + if (err < 0) + nl_cli_fatal(err, "Unable to delete cell: %s", nl_geterror(err)); + + printf("Deleted: "); + nl_object_dump(OBJ_CAST(cell), ¶ms); + return 0; +} + diff --git a/src/dect-cell-list.c b/src/dect-cell-list.c new file mode 100644 index 0000000..bb946ed --- /dev/null +++ b/src/dect-cell-list.c @@ -0,0 +1,24 @@ +#include "netlink/cli/utils.h" + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_cache *cell_cache; + struct nl_cache *cluster_cache; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_DECT); + if (nl_dect_cluster_alloc_cache(sock, &cluster_cache)) + exit(1); + nl_cache_mngt_provide(cluster_cache); + if (nl_dect_cell_alloc_cache(sock, &cell_cache)) + exit(1); + + nl_cache_dump(cell_cache, ¶ms); + return 0; +} + diff --git a/src/dect-cluster-add.c b/src/dect-cluster-add.c new file mode 100644 index 0000000..12db751 --- /dev/null +++ b/src/dect-cluster-add.c @@ -0,0 +1,95 @@ +#include "netlink/cli/utils.h" + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_dect_cluster *cl; + struct nl_dect_ari *pari; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int err; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_DECT); + cl = nl_dect_cluster_alloc(); + pari = (void *)nl_dect_cluster_get_pari(cl); + + for (;;) { + int c, optidx = 0; + enum { + ARG_NAME = 257, + ARG_MODE, + ARG_CLASS, + ARG_EMC, + ARG_EIC, + ARG_POC, + ARG_GOP, + ARG_FIL, + ARG_FPS, + ARG_FPN, + }; + static struct option long_opts[] = { + { "name", 1, 0, ARG_NAME }, + { "mode", 1, 0, ARG_MODE }, + { "class", 1, 0, ARG_CLASS }, + { "emc", 1, 0, ARG_EMC }, + { "eic", 1, 0, ARG_EIC }, + { "poc", 1, 0, ARG_POC }, + { "gop", 1, 0, ARG_GOP }, + { "fil", 1, 0, ARG_FIL }, + { "fps", 1, 0, ARG_FPS }, + { "fpn", 1, 0, ARG_FPN }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "qhvd:n:t:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'v': nl_cli_print_version(); break; + case ARG_NAME: + nl_dect_cluster_set_name(cl, strdup(optarg)); + break; + case ARG_MODE: + nl_dect_cluster_set_mode(cl, nl_dect_cluster_str2mode(optarg)); + break; + case ARG_CLASS: + nl_dect_ari_set_class(pari, nl_dect_ari_str2class(optarg)); + break; + case ARG_EMC: + nl_dect_ari_set_emc(pari, strtoul(optarg, NULL, 16)); + break; + case ARG_EIC: + nl_dect_ari_set_eic(pari, strtoul(optarg, NULL, 16)); + break; + case ARG_POC: + nl_dect_ari_set_poc(pari, strtoul(optarg, NULL, 16)); + break; + case ARG_GOP: + nl_dect_ari_set_gop(pari, strtoul(optarg, NULL, 16)); + break; + case ARG_FIL: + nl_dect_ari_set_fil(pari, strtoul(optarg, NULL, 16)); + break; + case ARG_FPS: + nl_dect_ari_set_fps(pari, strtoul(optarg, NULL, 16)); + break; + case ARG_FPN: + nl_dect_ari_set_fpn(pari, strtoul(optarg, NULL, 16)); + break; + } + } + + nl_dect_cluster_set_pari(cl, pari); + err = nl_dect_cluster_add(sock, cl, 0); + if (err < 0) + nl_cli_fatal(err, "Unable to add cluster: %s", nl_geterror(err)); + + printf("Added: "); + nl_object_dump(OBJ_CAST(cl), ¶ms); + return 0; +} + diff --git a/src/dect-cluster-delete.c b/src/dect-cluster-delete.c new file mode 100644 index 0000000..6e564ce --- /dev/null +++ b/src/dect-cluster-delete.c @@ -0,0 +1,64 @@ +#include "netlink/cli/utils.h" + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_dect_cluster *cl; + struct nl_dect_ari *pari; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int err; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_DECT); + cl = nl_dect_cluster_alloc(); + pari = (void *)nl_dect_cluster_get_pari(cl); + + for (;;) { + int c, optidx = 0; + enum { + ARG_NAME = 257, + ARG_MODE, + ARG_EMC, + ARG_FPN, + }; + static struct option long_opts[] = { + { "name", 1, 0, ARG_NAME }, + { "mode", 1, 0, ARG_MODE }, + { "emc", 1, 0, ARG_EMC }, + { "fpn", 1, 0, ARG_FPN }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "qhvd:n:t:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'v': nl_cli_print_version(); break; + case ARG_NAME: + nl_dect_cluster_set_name(cl, strdup(optarg)); + break; + case ARG_MODE: + nl_dect_cluster_set_mode(cl, atoi(optarg)); + break; + case ARG_EMC: + nl_dect_ari_set_emc(pari, strtoul(optarg, NULL, 16)); + break; + case ARG_FPN: + nl_dect_ari_set_fpn(pari, strtoul(optarg, NULL, 16)); + break; + } + } + + err = nl_dect_cluster_delete(sock, cl, 0); + if (err < 0) + nl_cli_fatal(err, "Unable to delete cluster: %s", nl_geterror(err)); + + printf("Deleted: "); + nl_object_dump(OBJ_CAST(cl), ¶ms); + return 0; +} + diff --git a/src/dect-cluster-list.c b/src/dect-cluster-list.c new file mode 100644 index 0000000..edff5fe --- /dev/null +++ b/src/dect-cluster-list.c @@ -0,0 +1,20 @@ +#include "netlink/cli/utils.h" + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_cache *cluster_cache; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_DECT); + if (nl_dect_cluster_alloc_cache(sock, &cluster_cache)) + exit(1); + + nl_cache_dump(cluster_cache, ¶ms); + return 0; +} + diff --git a/src/dect-llme-mac-con.c b/src/dect-llme-mac-con.c new file mode 100644 index 0000000..5acf6a7 --- /dev/null +++ b/src/dect-llme-mac-con.c @@ -0,0 +1,111 @@ +#if 0 +#include "utils.h" + +static void obj_input(struct nl_object *obj, void *arg) +{ + struct nl_dump_params dp = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + + printf("MAC Connection: "); + nl_object_dump(obj, &dp); + printf("\n"); +} + +static int event_input(struct nl_msg *msg, void *arg) +{ + if (nl_msg_parse(msg, &obj_input, NULL) < 0) + fprintf(stderr, "Unknown message type\n"); + return NL_STOP; +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_cache *cluster_cache; + struct dect_llme_msg *lmsg; + struct dect_ari *ari; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int index; + int err; + + sock = nlt_alloc_socket(); + nlt_connect(sock, NETLINK_DECT); + if (dect_cluster_alloc_cache(sock, &cluster_cache)) + exit(1); + nl_cache_mngt_provide(cluster_cache); + + lmsg = dect_llme_msg_alloc(); + dect_llme_msg_set_type(lmsg, DECT_LLME_MAC_CON); + + ari = (void *)dect_llme_mac_con_get_ari(lmsg); + + for (;;) { + int c, optidx = 0; + enum { + ARG_CLUSTER = 257, + ARG_MCEI, + ARG_PMID, + ARG_EMC, + ARG_FPN, + ARG_FPC, + }; + static struct option long_opts[] = { + { "cluster", 1, 0, ARG_CLUSTER }, + { "mcei", 1, 0, ARG_MCEI }, + { "pmid", 1, 0, ARG_PMID }, + { "emc", 1, 0, ARG_EMC }, + { "fpn", 1, 0, ARG_FPN }, + { "fpc", 0, 0, ARG_FPC }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "qhvd:n:t:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'v': nlt_print_version(); break; + case ARG_CLUSTER: + index = dect_cluster_name2i(cluster_cache, optarg); + dect_llme_msg_set_index(lmsg, index); + break; + case ARG_MCEI: + dect_llme_mac_con_set_mcei(lmsg, strtoul(optarg, NULL, 16)); + break; + case ARG_PMID: + dect_llme_mac_con_set_pmid(lmsg, strtoul(optarg, NULL, 16)); + break; + case ARG_EMC: + dect_ari_set_emc(ari, strtoul(optarg, NULL, 16)); + break; + case ARG_FPN: + dect_ari_set_fpn(ari, strtoul(optarg, NULL, 16)); + break; + case ARG_FPC: + dect_llme_mac_info_set_fpc(lmsg, 0); + dect_llme_mac_info_set_ehlc(lmsg, 0); + break; + } + } + + //dect_llme_mac_con_set_ari(lmsg, ari); + if ((err = dect_llme_request(sock, lmsg)) < 0) + fatal(err, "Unable to send request: %s", nl_geterror(err)); + + printf("Requested: "); + nl_object_dump(OBJ_CAST(lmsg), ¶ms); + + nl_socket_add_membership(sock, DECTNLGRP_LLME); + nl_socket_disable_seq_check(sock); + nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL); + while (1) + nl_recvmsgs_default(sock); + return 0; +} +#endif +int main() {} diff --git a/src/dect-llme-monitor.c b/src/dect-llme-monitor.c new file mode 100644 index 0000000..eba1536 --- /dev/null +++ b/src/dect-llme-monitor.c @@ -0,0 +1,37 @@ +#include "netlink/cli/utils.h" + +static void obj_input(struct nl_object *obj, void *arg) +{ + struct nl_dump_params dp = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + nl_object_dump(obj, &dp); +} + +static int event_input(struct nl_msg *msg, void *arg) +{ + if (nl_msg_parse(msg, &obj_input, NULL) < 0) + fprintf(stderr, "Unknown message type\n"); + return NL_STOP; +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_cache *cluster_cache; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_DECT); + if (nl_dect_cluster_alloc_cache(sock, &cluster_cache)) + exit(1); + nl_cache_mngt_provide(cluster_cache); + + nl_socket_add_membership(sock, DECTNLGRP_LLME); + nl_socket_disable_seq_check(sock); + nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL); + while (1) + nl_recvmsgs_default(sock); + return 0; +} + diff --git a/src/dect-llme-scan.c b/src/dect-llme-scan.c new file mode 100644 index 0000000..1d4980f --- /dev/null +++ b/src/dect-llme-scan.c @@ -0,0 +1,139 @@ +#include "netlink/cli/utils.h" + +#define CACHE_SIZE 64 + +static struct { + unsigned int index; + unsigned int used; + struct { + uint16_t emc; + uint32_t fpn; + uint8_t rpn; + } ids[CACHE_SIZE]; +} cache; + +static void add_ari(const struct nl_dect_llme_msg *lmsg) +{ + const struct nl_dect_ari *ari = nl_dect_llme_mac_info_get_pari(lmsg); + unsigned int index = cache.index; + + cache.ids[index].emc = nl_dect_ari_get_emc(ari); + cache.ids[index].fpn = nl_dect_ari_get_fpn(ari); + cache.ids[index].rpn = nl_dect_llme_mac_info_get_rpn(lmsg); + + if (++cache.used > CACHE_SIZE) + cache.used = CACHE_SIZE; + if (++cache.index == CACHE_SIZE) + cache.index = 0; +} + +static bool lookup_ari(const struct nl_dect_llme_msg *lmsg) +{ + const struct nl_dect_ari *ari = nl_dect_llme_mac_info_get_pari(lmsg); + unsigned int index; + + for (index = 0; index < cache.used; index++) { + if (cache.ids[index].emc == nl_dect_ari_get_emc(ari) && + cache.ids[index].fpn == nl_dect_ari_get_fpn(ari) && + cache.ids[index].rpn == nl_dect_llme_mac_info_get_rpn(lmsg)) + return true; + } + return false; +} + +static void obj_input(struct nl_object *obj, void *arg) +{ + struct nl_dect_llme_msg *lmsg = nl_object_priv(obj); + struct nl_dump_params dp = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + static unsigned int n; + + if (lookup_ari(lmsg)) + return; + add_ari(lmsg); + + printf("%u: Station: ", ++n); + nl_object_dump(obj, &dp); + printf("\n"); +} + +static int event_input(struct nl_msg *msg, void *arg) +{ + if (nl_msg_parse(msg, &obj_input, NULL) < 0) + fprintf(stderr, "Unknown message type\n"); + return NL_OK; +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_cache *cluster_cache; + struct nl_dect_llme_msg *lmsg; + struct nl_dect_ari *pari; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int index; + int err; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_DECT); + if (nl_dect_cluster_alloc_cache(sock, &cluster_cache)) + exit(1); + nl_cache_mngt_provide(cluster_cache); + + lmsg = nl_dect_llme_msg_alloc(); + nl_dect_llme_msg_set_type(lmsg, DECT_LLME_SCAN); + + pari = (void *)nl_dect_llme_mac_info_get_pari(lmsg); + + for (;;) { + int c, optidx = 0; + enum { + ARG_CLUSTER = 257, + ARG_EMC, + ARG_FPN, + }; + static struct option long_opts[] = { + { "cluster", 1, 0, ARG_CLUSTER }, + { "emc", 1, 0, ARG_EMC }, + { "fpn", 1, 0, ARG_FPN }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "qhvd:n:t:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'v': nl_cli_print_version(); break; + case ARG_CLUSTER: + index = nl_dect_cluster_name2i(cluster_cache, optarg); + nl_dect_llme_msg_set_index(lmsg, index); + break; + case ARG_EMC: + nl_dect_ari_set_emc(pari, strtoul(optarg, NULL, 16)); + break; + case ARG_FPN: + nl_dect_ari_set_fpn(pari, strtoul(optarg, NULL, 16)); + break; + } + } + + //nl_dect_llme_mac_info_set_pari(lmsg, pari); + if ((err = nl_dect_llme_request(sock, lmsg)) < 0) + nl_cli_fatal(err, "Unable to send request: %s", nl_geterror(err)); + + printf("Requested: "); + nl_object_dump(OBJ_CAST(lmsg), ¶ms); + + nl_socket_disable_seq_check(sock); + nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL); + while (1) + nl_recvmsgs_default(sock); + return 0; +} + diff --git a/src/dect-transceiver-bind.c b/src/dect-transceiver-bind.c new file mode 100644 index 0000000..97ad77e --- /dev/null +++ b/src/dect-transceiver-bind.c @@ -0,0 +1,62 @@ +#include "netlink/cli/utils.h" + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_dect_transceiver *trx; + struct nl_cache *cell_cache; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int err; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_DECT); + + if (nl_dect_cell_alloc_cache(sock, &cell_cache)) + exit(1); + nl_cache_mngt_provide(cell_cache); + + trx = nl_dect_transceiver_alloc(); + for (;;) { + int c, optidx = 0; + enum { + ARG_TRANSCEIVER = 257, + ARG_CELL, + ARG_UNBIND, + }; + static struct option long_opts[] = { + { "transceiver", 1, 0, ARG_TRANSCEIVER }, + { "cell", 1, 0, ARG_CELL }, + { "unbind", 0, 0, ARG_UNBIND }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "qhvd:n:t:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'v': nl_cli_print_version(); break; + case ARG_TRANSCEIVER: + nl_dect_transceiver_set_name(trx, strdup(optarg)); + break; + case ARG_CELL: + nl_dect_transceiver_set_link(trx, nl_dect_cell_name2i(cell_cache, optarg)); + break; + case ARG_UNBIND: + nl_dect_transceiver_set_link(trx, -1); + break; + } + } + + err = nl_dect_transceiver_change(sock, trx, 0); + if (err < 0) + nl_cli_fatal(err, "Unable to bind to cell: %s", nl_geterror(err)); + + printf("Bound: "); + nl_object_dump(OBJ_CAST(trx), ¶ms); + return 0; +} + diff --git a/src/dect-transceiver-list.c b/src/dect-transceiver-list.c new file mode 100644 index 0000000..c1e5cde --- /dev/null +++ b/src/dect-transceiver-list.c @@ -0,0 +1,60 @@ +#include "netlink/cli/utils.h" + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_cache *cell_cache; + struct nl_cache *transceiver_cache; + struct nl_dect_transceiver *trx; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_DECT); + + if (nl_dect_cell_alloc_cache(sock, &cell_cache)) + exit(1); + nl_cache_mngt_provide(cell_cache); + + if (nl_dect_transceiver_alloc_cache(sock, &transceiver_cache)) + exit(1); + trx = nl_dect_transceiver_alloc(); + if (trx == NULL) + exit(1); + + for (;;) { + int c, optidx = 0, cidx; + enum { + ARG_NAME = 257, + ARG_CELL, + }; + static struct option long_ops[] = { + { "name", 1, 0, ARG_NAME }, + { "cell", 1, 0, ARG_CELL }, + {} + }; + + c = getopt_long(argc, argv, "n:c:", long_ops, &optidx); + if (c == -1) + break; + switch (c) { + case ARG_NAME: + nl_dect_transceiver_set_name(trx, optarg); + break; + case ARG_CELL: + cidx = nl_dect_cell_name2i(cell_cache, optarg); + if (cidx == 0) { + fprintf(stderr, "cell %s does not exist\n", optarg); + exit(1); + } + nl_dect_transceiver_set_link(trx, cidx); + break; + } + } + + nl_cache_dump_filter(transceiver_cache, ¶ms, OBJ_CAST(trx)); + return 0; +} + |