dect
/
linux-2.6
Archived
13
0
Fork 0

dect: add DECT protocol core

Add an (so far unfunctional) DECT protocol core and a basic DECT netlink
socket family.

Signed-off-by: Patrick McHardy <kaber@trash.net>
This commit is contained in:
Patrick McHardy 2009-05-06 19:30:29 +02:00
parent 6c2fa86bf4
commit 28c157ecb4
34 changed files with 13242 additions and 4 deletions

View File

@ -53,6 +53,8 @@ header-y += cgroupstats.h
header-y += cramfs_fs.h
header-y += cycx_cfm.h
header-y += dcbnl.h
header-y += dect.h
header-y += dect_netlink.h
header-y += dlmconstants.h
header-y += dlm_device.h
header-y += dlm_netlink.h

76
include/linux/dect.h Normal file
View File

@ -0,0 +1,76 @@
#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;
};
/**
* struct sockaddr_dect_ssap
*
* @dect_family: family (AF_DECT)
* @dect_dlei: Data Link Endpoint Identifier
* @dect_class: Class A/B
*/
struct sockaddr_dect_ssap {
sa_family_t dect_family;
__u64 dect_ari:40,
dect_pmid:20,
dect_lcn:3;
__u8 dect_lln:4,
dect_sapi:4;
__u8 dect_class;
};
/**
* 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;
__u64 dect_ari:40,
dect_pmid:20,
dect_lcn:3;
};
#endif /* _LINUX_DECT_H */

View File

@ -0,0 +1,255 @@
#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_attrs {
DECTA_SLOT_UNSPEC,
DECTA_SLOT_NUM,
DECTA_SLOT_STATE,
DECTA_SLOT_CARRIER,
DECTA_SLOT_FREQUENCY,
DECTA_SLOT_RSSI,
DECTA_SLOT_RX_PACKETS,
DECTA_SLOT_RX_BYTES,
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)
enum dect_transceiver_attrs {
DECTA_TRANSCEIVER_UNSPEC,
DECTA_TRANSCEIVER_NAME,
DECTA_TRANSCEIVER_TYPE,
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),
};
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_cluster_attrs {
DECTA_CLUSTER_UNSPEC,
DECTA_CLUSTER_NAME,
DECTA_CLUSTER_MODE,
DECTA_CLUSTER_PARI,
DECTA_CLUSTER_CELLS,
__DECTA_CLUSTER_MAX
};
#define DECTA_CLUSTER_MAX (__DECTA_CLUSTER_MAX - 1)
enum dect_cluster_modes {
DECT_MODE_FP,
DECT_MODE_PP,
DECT_MODE_MONITOR,
};
/**
* 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 = 0x8000,
DECT_FPC_FULL_SLOT = 0x4000,
DECT_FPC_FREQ_CONTROL = 0x2000,
DECT_FPC_PAGE_REPETITION = 0x1000,
DECT_FPC_CO_SETUP_ON_DUMMY = 0x800,
DECT_FPC_CL_UPLINK = 0x400,
DECT_FPC_CL_DOWNLINK = 0x200,
DECT_FPC_BASIC_A_FIELD_SETUP = 0x100,
DECT_FPC_ADV_A_FIELD_SETUP = 0x80,
DECT_FPC_B_FIELD_SETUP = 0x40,
DECT_FPC_CF_MESSAGES = 0x20,
DECT_FPC_IN_MIN_DELAY = 0x10,
DECT_FPC_IN_NORM_DELAY = 0x8,
DECT_FPC_IP_ERROR_DETECTION = 0x4,
DECT_FPC_IP_ERROR_CORRECTION = 0x2,
DECT_FPC_MULTIBEARER_CONNECTIONS = 0x1,
};
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 = 0x800,
DECT_HLC_STANDARD_CIPHERING = 0x400,
DECT_HLC_LOCATION_REGISTRATION = 0x200,
DECT_HLC_SIM_SERVICES = 0x100,
DECT_HLC_NON_STATIC_FIXED_PART = 0x80,
DECT_HLC_CISS_SERVICE = 0x40,
DECT_HLC_CLMS_SERVICE = 0x20,
DECT_HLC_COMS_SERVICE = 0x10,
DECT_HLC_ACCESS_RIGHT_REQUESTS = 0x8,
DECT_HLC_EXTERNAL_HANDOVER = 0x4,
DECT_HLC_CONNECTION_HANDOVER = 0x2,
DECT_HLC_RESERVED = 0x1,
};
enum dect_extended_higher_layer_capabilities {
DECT_EHLC_ISDN_DATA_SERVICE = 0x1,
DECT_EHLC_DATA_SERVICE_PROFILE_A_B = 0x2,
DECT_EHLC_DATA_SERVICE_PROFILE_C = 0x4,
DECT_EHLC_DATA_SERVICE_PROFILE_D = 0x8,
DECT_EHLC_DATA_SERVICE_PROFILE_E = 0x10,
DECT_EHLC_DATA_SERVICE_PROFILE_F = 0x20,
DECT_EHLC_ASYMETRIC_BEARERS = 0x40,
DECT_EHLC_TPUI_LOCATION_REGISTRATION = 0x100,
};
enum dect_efpc_attrs {
DECTA_EFPC_UNSPEC,
DECTA_EFPC_CRFP_HOPS,
DECTA_EFPC_CRFP_ENCRYPTION,
DECTA_EFPC_REP_HOPS,
DECTA_EFPC_REP_INTERLACING,
DECTA_EFPC_EHLC,
__DECTA_EFPC_MAX
};
#define DECTA_EFPC_MAX (__DECTA_EFPC_MAX - 1)
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_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_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 */

View File

@ -24,6 +24,7 @@
/* leave room for NETLINK_DM (DM Events) */
#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
#define NETLINK_ECRYPTFS 19
#define NETLINK_DECT 20 /* DECT */
#define MAX_LINKS 32

View File

@ -194,7 +194,8 @@ struct ucred {
#define AF_RXRPC 33 /* RxRPC sockets */
#define AF_ISDN 34 /* mISDN sockets */
#define AF_PHONET 35 /* Phonet sockets */
#define AF_MAX 36 /* For now.. */
#define AF_DECT 36 /* DECT sockets */
#define AF_MAX 37 /* For now.. */
/* Protocol families, same as address families. */
#define PF_UNSPEC AF_UNSPEC
@ -233,6 +234,7 @@ struct ucred {
#define PF_RXRPC AF_RXRPC
#define PF_ISDN AF_ISDN
#define PF_PHONET AF_PHONET
#define PF_DECT AF_DECT
#define PF_MAX AF_MAX
/* Maximum queue length specifiable by listen. */
@ -303,6 +305,7 @@ struct ucred {
#define SOL_BLUETOOTH 274
#define SOL_PNPIPE 275
#define SOL_RDS 276
#define SOL_DECT 277
/* IPX options */
#define IPX_TYPE 1

75
include/net/dect/ccp.h Normal file
View File

@ -0,0 +1,75 @@
/*
* DECT MAC Layer - Cell Control Protocol (CCP)
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*/
#ifndef _NET_DECT_CCP
#define _NET_DECT_CCP
#define DECT_CCP_TIPC_TYPE TIPC_RESERVED_TYPES
#define DECT_CCP_CELL_PORT 1000
#define DECT_CCP_CLUSTER_PORT_BASE 1000
enum dect_ccp_primitives {
/* CCF -> CSF */
DECT_CCP_SET_MODE,
DECT_CCP_SCAN,
DECT_CCP_ENABLE,
DECT_CCP_PRELOAD,
DECT_CCP_TBC_INITIATE,
DECT_CCP_TBC_CONFIRM,
DECT_CCP_TBC_RELEASE,
/* CSF -> CCF */
DECT_CCP_MBC_CONN_INDICATE,
DECT_CCP_MBC_CONN_NOTIFY,
DECT_CCP_MBC_DATA_INDICATE,
};
struct dect_ccp_msg_hdr {
u8 primitive;
} __attribute__((packed));
struct dect_ccp_ari {
__be64 ari;
};
struct dect_ccp_mode_msg {
u8 mode;
} __attribute__((packed));
struct dect_ccp_scan_msg {
__be64 ari;
__be64 ari_mask;
} __attribute__((packed));
struct dect_ccp_sysinfo_msg {
__be64 pari;
__be64 sari[DECT_SARI_CYCLE_MAX];
__be64 fpc;
__be64 hlc;
__be64 efpc;
__be32 mfn;
u8 num_saris;
u8 rpn;
} __attribute__((packed));
struct dect_ccp_mbc_msg {
__be32 mcei;
__be32 pmid;
__be64 ari;
u8 ecn;
} __attribute__((packed));
struct dect_ccp_data_msg {
u8 channel;
u8 data[];
} __attribute__((packed));
extern int dect_ccp_cluster_init(struct dect_cluster *cl);
extern void dect_ccp_cluster_shutdown(struct dect_cluster *cl);
extern struct dect_cluster_handle *dect_ccp_cell_init(struct dect_cell *cell,
u8 clindex);
#endif /* _NET_DECT_CPP */

198
include/net/dect/dect.h Normal file
View File

@ -0,0 +1,198 @@
#ifndef _NET_DECT_DECT_H
#define _NET_DECT_DECT_H
#define DECT_FRAMES_PER_MULTIFRAME 16
static inline u8 dect_next_framenum(u8 framenum)
{
if (++framenum == DECT_FRAMES_PER_MULTIFRAME)
framenum = 0;
return framenum;
}
static inline u8 dect_framenum_add(u8 f1, u8 f2)
{
return (f1 + f2) % DECT_FRAMES_PER_MULTIFRAME;
}
#define DECT_MULTIFRAME_MASK 0x00ffffff
static inline u32 dect_next_mfn(u32 mfn)
{
if (++mfn == (1 << 24) - 1)
mfn = 0;
return mfn;
}
static inline u32 dect_mfn_add(u32 mfn1, u32 mfn2)
{
return (mfn1 + mfn2) & DECT_MULTIFRAME_MASK;
}
/* Compare multiframe numbers, considering overflows */
static inline bool dect_mfn_before(u32 mfn1, u32 mfn2)
{
return (s32)((mfn2 << 8) - (mfn1 << 8)) > 0;
}
static inline bool dect_mfn_after(u32 mfn1, u32 mfn2)
{
return dect_mfn_before(mfn2, mfn1);
}
#include <linux/dect.h>
#include <net/dect/identities.h>
#include <net/dect/mac_ccf.h>
#include <net/dect/dlc.h>
extern void __acquires(dect_cfg_mutex) dect_lock(void);
extern void __releases(dect_cfg_mutex) dect_unlock(void);
/**
* struct dect_cluster - DECT cluster of up to 8/256 cells
*
* @list: device list node
* @name: device identifier
* @index: unique numeric cluster identifier
* @mode: device mode (FP/PP/monitor)
* @pari: primary access rights identifier
* @si: system information
* @bmc: Broadcast Message Control
* @cmc: Connectionless Message Control
* @mbcs: Multi-Bearer Controllers
* @cells: DECT cells
*/
struct dect_cluster {
struct list_head list;
char name[DECTNAMSIZ];
int index;
u32 tipc_id;
u32 tipc_portref;
struct dect_cluster_handle handle;
enum dect_cluster_modes mode;
spinlock_t lock;
struct dect_ari pari;
struct dect_si si;
u32 pmid;
struct list_head cells;
struct dect_bmc bmc;
struct dect_cmc cmc;
struct list_head mbcs;
u32 mcei_rover;
struct list_head mac_connections;
};
extern void dect_cluster_init(struct dect_cluster *cl);
extern void dect_cluster_shutdown(struct dect_cluster *cl);
extern struct dect_cluster *dect_cluster_get_by_index(int index);
extern struct dect_cluster *dect_cluster_get_by_pari(const struct dect_ari *ari);
/**
* struct dect_llme_req - LLME netlink request
*
* @nlh: netlink header
* @nlpid: netlink socket PID
*/
struct dect_llme_req {
struct nlmsghdr nlh;
u32 nlpid;
};
struct dect_scan_result;
extern void dect_llme_scan_result_notify(const struct dect_cluster *cl,
const struct dect_scan_result *res);
#include <net/sock.h>
extern const struct proto_ops dect_stream_ops;
extern const struct proto_ops dect_dgram_ops;
struct dect_proto {
unsigned int type;
unsigned int protocol;
int capability;
const struct proto_ops *ops;
int (*getname)(struct sock *sk,
struct sockaddr *uaddr, int *len,
int peer);
struct proto proto;
};
#include <net/tcp_states.h>
enum {
DECT_SK_ESTABLISHED = TCP_ESTABLISHED,
DECT_SK_ESTABLISH_PENDING = TCP_SYN_SENT,
DECT_SK_RELEASED = TCP_CLOSE,
DECT_SK_RELEASE_PENDING = TCP_CLOSING,
DECT_SK_LISTEN = TCP_LISTEN,
};
struct dect_csk {
struct sock sk;
struct hlist_head accept_queue;
};
static inline struct dect_csk *dect_csk(const struct sock *sk)
{
return (struct dect_csk *)sk;
}
extern int dect_proto_register(struct dect_proto *proto);
extern void dect_proto_unregister(struct dect_proto *proto);
struct dect_skb_sk_cb {
//struct dect_skb_trx_cb cb;
int index;
};
#define DECT_SK_CB(skb) ((struct dect_skb_sk_cb *)(skb)->cb)
static inline int dect_sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
/*
* Release the transceiver reference, it is only valid in IRQ and
* softirq context.
*/
//FIXME
//DECT_SK_CB(skb)->index = DECT_CB(skb)->trx->dev->index;
return sock_queue_rcv_skb(sk, skb);
}
extern void (*dect_raw_rcv_hook)(struct sk_buff *skb);
static inline void dect_raw_rcv(struct sk_buff *skb)
{
typeof(dect_raw_rcv_hook) dect_raw_rcv;
rcu_read_lock();
dect_raw_rcv = dect_raw_rcv_hook;
if (dect_raw_rcv != NULL)
dect_raw_rcv(skb);
rcu_read_unlock();
}
extern int dect_af_module_init(void);
extern void dect_af_module_exit(void);
extern int dect_bsap_module_init(void);
extern void dect_bsap_module_exit(void);
extern int dect_ssap_module_init(void);
extern void dect_ssap_module_exit(void);
extern int dect_lu1_sap_module_init(void);
extern void dect_lu1_sap_module_exit(void);
extern int dect_netlink_module_init(void);
extern void dect_netlink_module_exit(void);
extern struct sk_buff *skb_append_frag(struct sk_buff *head, struct sk_buff *skb);
#endif /* _NET_DECT_DECT_H */

428
include/net/dect/dlc.h Normal file
View File

@ -0,0 +1,428 @@
/*
* DECT DLC Layer
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*/
#ifndef _NET_DECT_DLC_H
#define _NET_DECT_DLC_H
/*
* C-Plane data link service
*/
/*
* FA-Frame
*/
#define DECT_FA_HDR_SIZE 3
struct dect_fa_hdr {
u8 addr;
u8 ctrl;
u8 li;
};
/*
* Address field
*/
#define DECT_FA_ADDR_OFF 0
/* New link flag */
#define DECT_FA_ADDR_NLF_FLAG 0x80
/* Logical Link Number */
#define DECT_FA_ADDR_LLN_MASK 0x70
#define DECT_FA_ADDR_LLN_SHIFT 4
/* Service Access Point Identifier */
#define DECT_FA_ADDR_SAPI_MASK 0x0c
#define DECT_FA_ADDR_SAPI_SHIFT 2
/* Command/Response flag */
#define DECT_FA_ADDR_CR_FLAG 0x02
/* Reserved bit */
#define DECT_FA_ADDR_RES_BIT 0x01
/*
* Control field
*/
#define DECT_FA_CTRL_OFF 1
/*
* I-Format: numbered information
*/
#define DECT_FA_CTRL_I_FMT_MASK 0x01
#define DECT_FA_CTRL_I_FMT_ID 0x00
/* Receive sequence number */
#define DECT_FA_CTRL_I_NR_MASK 0xe0
#define DECT_FA_CTRL_I_NR_SHIFT 5
/* Poll bit */
#define DECT_FA_CTRL_I_P_FLAG 0x10
/* Send sequence number */
#define DECT_FA_CTRL_I_NS_MASK 0x0e
#define DECT_FA_CTRL_I_NS_SHIFT 1
/* Command */
#define DECT_FA_CTRL_I_CMD_I (0x0)
/*
* S-Format: supervisory functions
*/
#define DECT_FA_CTRL_S_FMT_MASK 0x03
#define DECT_FA_CTRL_S_FMT_ID 0x01
/* Receive sequence number */
#define DECT_FA_CTRL_S_NR_MASK 0xe0
#define DECT_FA_CTRL_S_NR_SHIFT 5
/* Poll/final bit */
#define DECT_FA_CTRL_S_PF_FLAG 0x10
/* Command/Response */
#define DECT_FA_CTRL_S_CR_MASK 0x0c
#define DECT_FA_CTRL_S_CR_RR 0x00
#define DECT_FA_CTRL_S_CR_RNR 0x40
#define DECT_FA_CTRL_S_CR_REJ 0x80
/*
* U-Format: unnumbered information
*/
#define DECT_FA_CTRL_U_FMT_MASK 0x03
#define DECT_FA_CTRL_U_FMT_ID 0x03
/* Unnumbered function bits */
#define DECT_FA_CTRL_U_U1_MASK 0xec
/* Poll/final bit */
#define DECT_FA_CTRL_U_PF_FLAG 0x10
/* Command/Response */
#define DECT_FA_CTRL_U_CR_MASK 0xef
#define DECT_FA_CTRL_U_CR_SABM 0x2c
#define DECT_FA_CTRL_U_CR_DM 0x0c
#define DECT_FA_CTRL_U_CR_UI 0x00
#define DECT_FA_CTRL_U_CR_DISC 0x40
#define DECT_FA_CTRL_U_CR_UA 0x60
/*
* Length Indicator
*/
#define DECT_FA_LI_OFF 2
/* Length (octets) */
#define DECT_FA_LI_LENGTH_MASK 0xfc
#define DECT_FA_LI_LENGTH_SHIFT 2
/* More data flag */
#define DECT_FA_LI_M_FLAG 0x02
/* Extended length indicator bit */
#define DECT_FA_LI_EXT_FLAG 0x01
/* maximum length value */
#define DECT_FA_LI_MAX 63
/*
* Extended Length indicator
*/
#define DECT_FA_ELI_OFF 3
/* Length (octets) */
#define DECT_FA_ELI_LENGTH_MASK 0xfc
#define DECT_FA_ELI_LENGTH_SHIFT 2
struct dect_fa_len {
u8 len;
bool more;
};
/*
* Fill Field
*/
#define DECT_FA_FILL_PATTERN 0xf0
/*
* Checksum field
*/
#define DECT_FA_CSUM_SIZE 2
/*
* Information field
*/
#define DECT_FA_I_MAX (DECT_FA_LI_MAX - DECT_FA_HDR_SIZE - DECT_FA_CSUM_SIZE)
/**
* struct dect_dli - DECT Data Link Identifier (DLI)
*
* @lln: Logical Link Number
* @mci: Mac Connection Identifier
*/
struct dect_dli {
enum dect_llns lln;
struct dect_mci mci;
};
/**
* @DECT_LAPC_ULI: unassigned link identifier state (class U/A)
* @DECT_LAPC_ALI: assigned link identifier state (class B established)
* @DECT_LAPC_ASM: assigned Link Identifier/multiple frame state (class B suspended)
*/
enum dect_lapc_states {
DECT_LAPC_ULI,
DECT_LAPC_ALI,
DECT_LAPC_ASM,
};
/**
* struct dect_lapc - DECT LAPC entity
*
* @lc: Associated Lc entity
* @dli: Data Link Identifier
* @sapi: Service Access Point Identifier
* @cmd: CR bit setting for commands (PT: 1, FT: 0)
* @nlf: New link flag
* @v_s: Send state Variable V(S): sequence number of next I-frame
* @v_a: Acknowledge state Variable V(A): last I-frame that has been acknowledged
* @v_r: Receive state Variable V(R): next expected sequence number
* @peer_busy: Peer is in receiver busy condition
* @window: maximum number of oustanding unacknowledged I-frames
* @mod: modulus for sequence number calculations
* @timer: Retransmission timer (DL.04)
* @rcnt: Retransmission counter
*/
struct dect_lapc {
struct sock *sk;
struct dect_lc *lc;
struct dect_dli dli;
enum dect_sapis sapi;
bool cmd;
enum dect_lapc_states state;
bool nlf;
u8 v_s;
u8 v_a;
u8 v_r;
struct sk_buff_head retransq;
bool busy;
bool peer_busy;
u8 window;
u8 mod;
u8 rcnt;
struct timer_list timer;
struct sk_buff *rcv_head;
};
/* class A window size and sequence number modulus */
#define DECT_LAPC_CLASS_A_WINDOW 1
#define DECT_LAPC_CLASS_A_MOD 2
/* class B window size and sequence number modulus */
#define DECT_LAPC_CLASS_B_INITIAL_WINDOW 1
#define DECT_LAPC_CLASS_B_WINDOW 3
#define DECT_LAPC_CLASS_B_MOD 8
/* maximum number of retransmissions */
#define DECT_LAPC_RETRANS_MAX 3
/* various timer parameters specified in Annex A */
#define DECT_LAPC_CLASS_A_ESTABLISH_TIMEOUT (2 * HZ)
#define DECT_LAPC_CLASS_B_ESTABLISH_TIMEOUT (2 * HZ)
#define DECT_LAPC_RETRANSMISSION_TIMEOUT (1 * HZ)
#define DECT_LAPC_LINK_RELEASE_TIMEOUT (2 * HZ)
#define DECT_LAPC_LINK_SUSPEND_TIMEOUT (2 * HZ)
#define DECT_LAPC_LINK_RESUME_TIMEOUT (2 * HZ)
#define DECT_LAPC_CONNECTION_HANDOVER_TIMEOUT (10 * HZ)
#define DECT_LAPC_CONNECTION_HANDOVER_INTERVAL (4 * HZ)
extern struct dect_lapc *dect_lapc_init(const struct dect_dli *dli,
enum dect_sapis sapi,
struct dect_lc *lc, gfp_t gfp);
extern void dect_lapc_release(struct dect_lapc *lapc);
extern int dect_lapc_transmit(struct dect_lapc *lapc);
extern int dect_lapc_establish(struct dect_lapc *lapc);
extern struct dect_lapc *dect_ssap_rcv_request(struct dect_lc *lc,
const struct dect_dli *dli,
enum dect_sapis sapi);
/**
* struct dect_lc - DECT Lc entity
*
* @mc: MAC connection
* @lsig: link signature for checksumming (lower 16 bits of PMID or 0)
* @rx_head: reassembly queue head
* @rx_len: target length of current reassembly buffer
* @txq: transmit queue
* @tx_head: current TX LAPC frame
* @tx_len: TX target fragment length
* @lapcs: LAPC entities associated with the Lc
* @e_lapc: LAPC performing establishment procedures
*
* The Lc entity is responsible for framing, logical channel selection and
* fragmenting of LAPC PDUs. There is one Lc entity per MAC connection.
*/
struct dect_lc {
struct dect_mac_conn *mc;
u16 lsig;
struct sk_buff *rx_head;
u8 rx_len;
struct sk_buff_head txq;
struct sk_buff *tx_head;
u8 tx_len;
struct dect_lapc *lapcs[DECT_LLN_MAX + 1];
struct dect_lapc *elapc;
};
#define DECT_LC_LSIG_MASK 0xffff
extern struct dect_lc *dect_lc_init(struct dect_mac_conn *mc, gfp_t gfp);
/**
* struct dect_lb - DECT Lb entity (C-plane broadcast service)
*
*
*/
struct dect_lb {
};
#define DECT_LB_SHORT_FRAME_SIZE 3
#define DECT_LB_LONG_FRAME_SIZE 5
#define DECT_LB_EXTENDED_FRAME_SIZE_MAX (6 * DECT_LB_LONG_FRAME_SIZE)
#include <net/sock.h>
/**
* struct dect_dlc_fbx_ops - DLC U-plane lower (FBx) entity ops
*
*/
struct dect_fbx;
struct dect_fbx_ops {
struct sk_buff *(*dequeue)(struct dect_fbx *fbx);
void (*enqueue)(struct dect_fbx *fbx,
struct sk_buff *skb);
};
struct dect_fbx {
const struct dect_fbx_ops *ops;
};
extern const struct dect_fbx_ops dect_fbn_ops;
struct dect_lux;
struct dect_lux_ops {
struct sk_buff *(*dequeue)(struct dect_lux *lux);
void (*enqueue)(struct dect_lux *lux,
struct sk_buff *skb);
void (*disconnect)(struct dect_lux *lux);
};
/**
* struct dect_lux - DLC U-plane upper (LUx) entity
*
* @fpx: FBx entity
*/
struct dect_lux {
const struct dect_lux_ops *ops;
struct dect_fbx fbx;
};
/**
* dect_mac_connection_states - DECT MAC connection states as viewed by the DLC
*
* @DECT_MAC_CONN_CLOSED:
* @DECT_MAC_CONN_OPEN_PENDING:
* @DECT_MAC_CONN_OPEN:
*/
enum dect_mac_conn_states {
DECT_MAC_CONN_CLOSED,
DECT_MAC_CONN_OPEN_PENDING,
DECT_MAC_CONN_OPEN,
};
/**
* struct dect_mac_conn - DECT MAC connection as viewed by the DLC
*
* @list: Cluster connection list node
* @cl: Cluster
* @mcei: MAC Connection Endpoint Identification
* @mci: MAC Connection Identifier (BMCI or AMCI)
* @state: Connection state
* @service: Service offered by the connection
*/
struct dect_mac_conn {
struct list_head list;
struct dect_cluster *cl;
u32 mcei;
struct dect_mci mci;
enum dect_mac_conn_states state;
enum dect_mac_service_types service;
struct dect_lc *lc;
struct dect_fbx *fbx;
};
extern struct dect_mac_conn *dect_mac_conn_init(struct dect_cluster *cl,
const struct dect_mci *mci,
const struct dect_mbc_id *id);
extern struct dect_mac_conn *dect_mac_conn_get_by_mci(const struct dect_cluster *cl,
const struct dect_mci *mci);
extern int dect_dlc_mac_conn_establish(struct dect_mac_conn *mc);
extern void dect_dlc_mac_conn_release(struct dect_mac_conn *mc);
extern int dect_dlc_mac_conn_confirm(struct dect_cluster *cl, u32 mcei,
enum dect_mac_service_types service);
extern int dect_dlc_mac_conn_indicate(struct dect_cluster *cl,
const struct dect_mbc_id *id);
extern int dect_dlc_mac_conn_disconnect(struct dect_cluster *cl, u32 mcei);
extern void dect_cplane_notify_state_change(struct dect_mac_conn *mc);
extern void dect_cplane_rcv(struct dect_mac_conn *mc,
enum dect_data_channels chan,
struct sk_buff *skb);
extern struct sk_buff *dect_cplane_dtr(struct dect_mac_conn *mc,
enum dect_data_channels chan);
extern void dect_uplane_rcv(struct dect_mac_conn *mc,
enum dect_data_channels chan,
struct sk_buff *skb);
extern struct sk_buff *dect_uplane_dtr(struct dect_mac_conn *mc,
enum dect_data_channels chan);
extern void dect_dlc_mac_co_data_indicate(struct dect_cluster *cl, u32 mcei,
enum dect_data_channels chan,
struct sk_buff *skb);
extern struct sk_buff *dect_dlc_mac_co_dtr_indicate(struct dect_cluster *cl, u32 mcei,
enum dect_data_channels chan);
extern void dect_bsap_rcv(const struct dect_cluster *cl, struct sk_buff *skb);
extern void dect_dlc_mac_page_indicate(struct dect_cluster *cl,
struct sk_buff *skb);
#endif /* _NET_DECT_DLC_H */

View File

@ -0,0 +1,223 @@
#ifndef _NET_DECT_IDENTITIES_H
#define _NET_DECT_IDENTITIES_H
/*
* Acess Rights Identity (ARI)
*/
#define DECT_ARI_ARC_MASK 0xe000000000000000ULL
#define DECT_ARI_ARC_SHIFT 61
/* Class A */
#define DECT_ARI_A_EMC_MASK 0x1fffe00000000000ULL
#define DECT_ARI_A_EMC_SHIFT 45
#define DECT_ARI_A_FPN_MASK 0x00001ffff0000000ULL
#define DECT_ARI_A_FPN_SHIFT 28
/* Class B */
#define DECT_ARI_B_EIC_MASK 0x1fffe00000000000ULL
#define DECT_ARI_B_EIC_SHIFT 45
#define DECT_ARI_B_FPN_MASK 0x00001fe000000000ULL
#define DECT_ARI_B_FPN_SHIFT 37
#define DECT_ARI_B_FPS_MASK 0x0000001e00000000ULL
#define DECT_ARI_B_FPS_SHIFT 33
/* Class C */
#define DECT_ARI_C_POC_MASK 0x1fffe00000000000ULL
#define DECT_ARI_C_POC_SHIFT 45
#define DECT_ARI_C_FPN_MASK 0x00001fe000000000ULL
#define DECT_ARI_C_FPN_SHIFT 37
#define DECT_ARI_C_FPS_MASK 0x0000001e00000000ULL
#define DECT_ARI_C_FPS_SHIFT 33
/* Class D */
#define DECT_ARI_D_GOP_MASK 0x1ffffe0000000000ULL
#define DECT_ARI_D_GOP_SHIFT 41
#define DECT_ARI_D_FPN_MASK 0x000001fe00000000ULL
#define DECT_ARI_D_FPN_SHIFT 33
/* Class E */
#define DECT_ARI_E_FIL_MASK 0x1fffe00000000000ULL
#define DECT_ARI_E_FIL_SHIFT 45
#define DECT_ARI_E_FPN_MASK 0x00001ffe00000000ULL
#define DECT_ARI_E_FPN_SHIFT 33
#include <linux/dect_netlink.h>
struct dect_ari {
enum dect_ari_classes arc;
u32 fpn;
u32 fps;
union {
u16 emc;
u16 eic;
u16 poc;
u32 gop;
u16 fil;
};
};
enum dect_ari_lengths {
DECT_ARC_A_LEN = 36,
DECT_ARC_B_LEN = 31,
DECT_ARC_C_LEN = 31,
DECT_ARC_D_LEN = 31,
DECT_ARC_E_LEN = 31,
};
extern bool dect_ari_masked_cmp(const struct dect_ari *a1,
const struct dect_ari *a2,
const struct dect_ari *m);
extern bool dect_ari_cmp(const struct dect_ari *a1, const struct dect_ari *a2);
extern u8 dect_parse_ari(struct dect_ari *ari, u64 a);
extern u64 dect_build_ari(const struct dect_ari *ari);
/*
* RFPI
*/
#define DECT_RFPI_E_FLAG 0x8000000000000000ULL
#define DECT_RFPI_ARI_SHIFT 1
#define DECT_RFPI_RPN_SHIFT 24
struct dect_idi;
extern bool dect_rfpi_cmp(const struct dect_idi *i1, const struct dect_idi *i2);
extern u64 dect_build_rfpi(const struct dect_idi *idi);
/*
* FMID (Fixed MAC Identifier)
*/
#define DECT_FMID_MASK 0x0fff
#define DECT_FMID_SIZE 12
extern u16 dect_build_fmid(const struct dect_idi *idi);
/*
* PMID (Portable MAC Identifier)
*/
#define DECT_PMID_MASK 0x000fffff
#define DECT_PMID_SIZE 20
#define DECT_PMID_DEFAULT_ID_MASK 0x000f0000
#define DECT_PMID_DEFAULT_ID 0x000e0000
#define DECT_PMID_DEFAULT_NUM_MASK 0x0000ffff
#define DECT_PMID_EMERGENCY_ID_MASK 0x000ff000
#define DECT_PMID_EMERGENCY_ID 0x000f1000
#define DECT_PMID_EMERGENCY_TPUI_MASK 0x00000fff
#define DECT_PMID_ASSIGNED_TPUI_MASK 0x000fffff
/**
* @DECT_PMID_DEFAULT: 1110 + arbitrary number (16 bits)
* @DECT_PMID_ASSIGNED: Assigned individual TPUI
* @DECT_PMID_EMERGENCY: 1111 0001 + 12 bits of emergency TPUI
*/
enum dect_pmid_types {
DECT_PMID_DEFAULT,
DECT_PMID_ASSIGNED,
DECT_PMID_EMERGENCY,
};
struct dect_pmid {
enum dect_pmid_types type;
union {
u32 tpui;
u32 num;
};
};
extern void dect_parse_pmid(struct dect_pmid *pmid, u32 p);
extern u32 dect_build_pmid(const struct dect_pmid *pmid);
extern bool dect_pmid_cmp(const struct dect_pmid *p1, const struct dect_pmid *p2);
/*
* ECN (Exchanged Connection Number)
*/
#define DECT_ECN_MASK 0xf
#define DECT_ECN_SIZE 4
/*
* LCN (Logical Connection Number)
*/
#define DECT_LCN_MASK 0x7
#define DECT_LCN_SIZE 3
/**
* struct dect_mci - MAC connection identifier
*
* @ari: DECT ARI
* @pmid: Portable MAC Identity
* @lcn: Logical Connection Number
*/
struct dect_mci {
struct dect_ari ari;
struct dect_pmid pmid;
u8 lcn;
};
extern int dect_parse_mci(struct dect_mci *mci, u64 m);
extern u64 dect_build_mci(const struct dect_mci *mci);
/*
* Data Link Identifier
*/
/**
* enum dect_sapis - S SAP Identifier
*
* @DECT_SAPI_CO_SIGNALLING: connection oriented signalling
* @DECT_SAPI_CL_SIGNALLING: connectionless signalling
*/
enum dect_sapis {
DECT_SAPI_CO_SIGNALLING = 0,
DECT_SAPI_CL_SIGNALLING = 3,
};
/**
* 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)
*/
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_MAX
};
#define DECT_LLN_MAX (__DECT_LLN_MAX - 1)
/**
* struct dect_dlei - DECT Data Link Endpoint Identifier (DLEI)
*
*/
struct dect_dlei {
struct dect_mci mci;
enum dect_sapis sapi;
enum dect_llns lln;
};
/**
* struct dect_ulei - DECT U-Plane Link Endpoint Identifier
*/
struct dect_ulei {
struct dect_mci mci;
};
#endif /* _NET_DECT_IDENTITIES_H */

698
include/net/dect/mac.h Normal file
View File

@ -0,0 +1,698 @@
/*
* DECT MAC Layer - Header and global definitions
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*/
#ifndef _NET_DECT_MAC_H
#define _NET_DECT_MAC_H
#include <net/dect/identities.h>
/*
* A-Field
*/
#define DECT_A_FIELD_SIZE 8
#define DECT_RA_FIELD_SIZE 2
#define DECT_RA_FIELD_OFF 6
/*
* Header field
*/
#define DECT_HDR_FIELD_SIZE 1
#define DECT_HDR_FIELD_OFF 0
#define DECT_HDR_TA_OFF 0
#define DECT_HDR_TA_MASK 0xe0
#define DECT_HDR_TA_SHIFT 5
#define DECT_HDR_Q1_OFF 0
#define DECT_HDR_Q1_FLAG 0x10
#define DECT_HDR_BA_OFF 0
#define DECT_HDR_BA_MASK 0x0e
#define DECT_HDR_BA_SHIFT 1
#define DECT_HDR_Q2_OFF 0
#define DECT_HDR_Q2_FLAG 0x01
/*
* T-Field
*/
#define DECT_T_FIELD_OFF 1
#define DECT_T_FIELD_SIZE 5
/**
* dect_tail_identification - MAC layer T-Field identification
*
* @DECT_TI_CT_PKT_0: C_T data packet number 0
* @DECT_TI_CT_PKT_1: C_T data packet number 1
* @DECT_TI_NT_CL: Identities information on connectionless bearer
* @DECT_TI_NT: Identities information
* @DECT_TI_QT: Multiframe synchronisation und system information
* @DECT_TI_RESERVED: Reserved
* @DECT_TI_MT: MAC layer control
* @DECT_TI_PT: Paging tail (RFP only)
* @DECT_TI_MT_PKT_0: MAC layer control (first PP transmission, PP only)
*/
enum dect_tail_identifications {
DECT_TI_CT_PKT_0 = 0x0 << DECT_HDR_TA_SHIFT,
DECT_TI_CT_PKT_1 = 0x1 << DECT_HDR_TA_SHIFT,
DECT_TI_NT_CL = 0x2 << DECT_HDR_TA_SHIFT,
DECT_TI_NT = 0x3 << DECT_HDR_TA_SHIFT,
DECT_TI_QT = 0x4 << DECT_HDR_TA_SHIFT,
DECT_TI_RESERVED = 0x5 << DECT_HDR_TA_SHIFT,
DECT_TI_MT = 0x6 << DECT_HDR_TA_SHIFT,
DECT_TI_PT = 0x7 << DECT_HDR_TA_SHIFT,
DECT_TI_MT_PKT_0 = 0x7 << DECT_HDR_TA_SHIFT,
};
struct dect_skb_a_cb {
enum dect_tail_identifications id;
};
#define DECT_A_CB(skb) ((struct dect_skb_a_cb *)(skb)->cb)
/*
* Identities channel (N-channel)
*/
/* Identities information */
#define DECT_NT_ID_RFPI_LEN 5
/**
* @e: indicates whether SARIs are available
* @pari: primary access rights identifier
* @rpn: radio part number
*/
struct dect_idi {
bool e;
struct dect_ari pari;
u8 rpn;
};
/*
* System information and multiframe marker (Q-channel)
*/
/* RFP Q-channel T-MUX rules: only frame 8 */
#define DECT_Q_CHANNEL_FRAME 8
/* System information header */
#define DECT_QT_H_MASK 0xf000000000000000ULL
#define DECT_QT_H_SHIFT 60
/**
* dect_system_information_types - codes for system information messages
*
* @DECT_QT_SI_SSI: static system information
* @DECT_QT_SI_ERFC: extended RF carriers
* @DECT_QT_SI_FPC: fixed part capabilities
* @DECT_QT_SI_EFPC: extended fixed part capabilities
* @DECT_QT_SI_SARI: SARI list contents
* @DECT_QT_SI_MFN: multi-frame number
* @DECT_QT_SI_ESC: escape
* @DECT_QT_SI_ERFC2: extended RF carriers part 2
* @DECT_QT_SI_TXI transmit information
* @DECT_QT_SI_EFPC2: extended fixed part capabilities part 2
*/
enum dect_mac_system_information_types {
DECT_QT_SI_SSI = 0x0ULL << DECT_QT_H_SHIFT,
DECT_QT_SI_SSI2 = 0x1ULL << DECT_QT_H_SHIFT,
DECT_QT_SI_ERFC = 0x2ULL << DECT_QT_H_SHIFT,
DECT_QT_SI_FPC = 0x3ULL << DECT_QT_H_SHIFT,
DECT_QT_SI_EFPC = 0x4ULL << DECT_QT_H_SHIFT,
DECT_QT_SI_SARI = 0x5ULL << DECT_QT_H_SHIFT,
DECT_QT_SI_MFN = 0x6ULL << DECT_QT_H_SHIFT,
DECT_QT_SI_ESC = 0x7ULL << DECT_QT_H_SHIFT,
DECT_QT_SI_ERFC2 = 0x9ULL << DECT_QT_H_SHIFT,
DECT_QT_SI_TXI = 0x10ULL << DECT_QT_H_SHIFT,
DECT_QT_SI_EFPC2 = 0x11ULL << DECT_QT_H_SHIFT,
};
/*
* Static system information - repeated every 8 multiframes
*/
#define DECT_QT_SSI_FREQ 8
/* normal reverse */
#define DECT_QT_SSI_NR_FLAG 0x1000000000000000ULL
/* slot number */
#define DECT_QT_SSI_SN_MASK 0x0f00000000000000ULL
#define DECT_QT_SSI_SN_SHIFT 56
/* start position */
#define DECT_QT_SSI_SP_MASK 0x00c0000000000000ULL
#define DECT_QT_SSI_SP_SHIFT 54
/* escape bit */
#define DECT_QT_SSI_ESC_FLAG 0x0020000000000000ULL
/* number of transceivers */
#define DECT_QT_SSI_TXS_MASK 0x0018000000000000ULL
#define DECT_QT_SSI_TXS_SHIFT 51
/* extended RF carrier information available */
#define DECT_QT_SSI_MC_FLAG 0x0004000000000000ULL
/* RF carriers available */
#define DECT_QT_SSI_RFCARS_MASK 0x0003ff0000000000ULL
#define DECT_QT_SSI_RFCARS_SHIFT 40
/* carrier number */
#define DECT_QT_SSI_CN_MASK 0x0000003f00000000ULL
#define DECT_QT_SSI_CN_SHIFT 32
/* primary scan carrier number */
#define DECT_QT_SSI_PSCN_MASK 0x000000003f000000ULL
#define DECT_QT_SSI_PSCN_SHIFT 24
struct dect_ssi {
bool nr;
bool mc;
u16 rfcars;
u8 sn;
u8 sp;
u8 txs;
u8 cn;
u8 pscn;
};
/*
* Extended RF carrier information
*/
#define DECT_QT_ERFC_FREQ 8
#define DECT_QT_ERFC_RFCARS_MASK 0x0fffffe000000000ULL
#define DECT_QT_ERFC_RFCARS_SHIFT 9
#define DECT_QT_ERFC_RFBAND_MASK 0x0000001f00000000ULL
#define DECT_QT_ERFC_RFBAND_SHIFT 32
#define DECT_QT_ERFC_ERFC2_FLAG 0x0000000080000000ULL
#define DECT_QT_ERFC_NUM_RFCARS_MASK 0x000000003f000000ULL
#define DECT_QT_ERFC_NUM_RFCARS_SHIFT 24
struct dect_erfc {
u32 rfcars;
u8 band;
u8 num_rfcars;
bool erfc2;
};
/*
* Fixed Part capabilities
*/
#define DECT_QT_FPC_FREQ 8
#define DECT_QT_FPC_CAPABILITY_MASK 0x0fffff0000000000ULL
#define DECT_QT_FPC_CAPABILITY_SHIFT 40
#define DECT_QT_FPC_HLC_MASK 0x000000ffff000000ULL
#define DECT_QT_FPC_HLC_SHIFT 24
struct dect_fpc {
u32 fpc;
u16 hlc;
};
/*
* Extended Fixed Part capabilities
*/
#define DECT_QT_EFPC_CRFP_HOPS_MASK 0x0c00000000000000ULL
#define DECT_QT_EFPC_CRFP_HOPS_SHIFT 58
#define DECT_QT_EFPC_CRFP_ENC_FLAG 0x0200000000000000ULL
#define DECT_QT_EFPC_REP_HOPS_MASK 0x0180000000000000ULL
#define DECT_QT_EFPC_REP_HOPS_SHIFT 55
#define DECT_QT_EFPC_REP_INTERLACE_FLAG 0x0040000000000000ULL
#define DECT_QT_EFPC_EHLC_MASK 0x000000017f000000ULL
#define DECT_QT_EFPC_EHLC_SHIFT 24
struct dect_efpc {
u8 crfp;
bool crfp_enc;
u8 rep;
bool rep_il;
u16 ehlc;
};
/*
* SARI message
*/
#define DECT_QT_SARI_FREQ 4
#define DECT_QT_SARI_LIST_CYCLE_MASK 0x000e000000000000ULL
#define DECT_QT_SARI_LIST_CYCLE_SHIFT 49
#define DECT_QT_SARI_TARI_FLAG 0x0001000000000000ULL
#define DECT_QT_SARI_BLACK_FLAG 0x0000800000000000ULL
#define DECT_QT_SARI_ARI_MASK 0x00007fffffff0000ULL
#define DECT_QT_SARI_ARI_SHIFT 17
struct dect_sari {
u8 list_cycle;
bool tari;
bool black;
struct dect_ari ari;
};
#define DECT_SARI_CYCLE_MAX 16
/*
* Multiframe number - repeated every 8 multiframes if supported
*/
#define DECT_QT_MFN_FREQ 8
#define DECT_QT_MFN_MASK 0x0000ffffff000000ULL
#define DECT_QT_MFN_SHIFT 24
struct dect_mfn {
u32 num;
};
/*
* Extended RF carrier information part 2
*/
#define DECT_QT_TXI_ERFC2_FREQ 8
#define DECT_QT_ERFC2_RFCARS_MASK 0x0fffffffe0000000ULL
#define DECT_QT_ERFC2_RFCARS_SHIFT 29
struct dect_erfc2 {
u32 rfcars;
};
/*
* Transmit Information
*/
#define DECT_QT_TXI_FREQ 8
#define DECT_QT_TXI_TYPE_MASK 0x0f00000000000000ULL
#define DECT_QT_TXI_TYPE_SHIFT 56
#define DECT_QT_TXI_PWL_MASK 0x00ff000000000000ULL
#define DECT_QT_TXI_PWL_SHIFT 48
/*
* Extended fixed part capabilitiees part 2
*/
/*
* Paging Tail (P-channel)
*/
#define DECT_PT_HDR_EXTEND_FLAG 0x8000000000000000ULL
#define DECT_PT_HDR_LENGTH_MASK 0x7000000000000000ULL
#define DECT_PT_HDR_LENGTH_SHIFT 60
/**
* @DECT_PT_ZERO_PAGE: zero length page
* @DECT_PT_SHORT_PAGE: short page
* @DECT_PT_FULL_PAGE: full page
* @DECT_PT_MAX_RESUME_PAGE: MAC resume and control page
* @DECT_PT_LONG_PAGE: not the last 36 bits of a long page
* @DECT_PT_LONG_PAGE_FIRST: the first 36 bits of a long page
* @DECT_PT_LONG_PAGE_LAST: the last 36 bits of a long page
* @DECT_PT_LONG_PAGE_ALL: all of a long page (first and last)
*
*/
enum dect_page_lengths {
DECT_PT_ZERO_PAGE = 0x0ULL << DECT_PT_HDR_LENGTH_SHIFT,
DECT_PT_SHORT_PAGE = 0x1ULL << DECT_PT_HDR_LENGTH_SHIFT,
DECT_PT_FULL_PAGE = 0x2ULL << DECT_PT_HDR_LENGTH_SHIFT,
DECT_PT_RESUME_PAGE = 0x3ULL << DECT_PT_HDR_LENGTH_SHIFT,
DECT_PT_LONG_PAGE = 0x4ULL << DECT_PT_HDR_LENGTH_SHIFT,
DECT_PT_LONG_PAGE_FIRST = 0x5ULL << DECT_PT_HDR_LENGTH_SHIFT,
DECT_PT_LONG_PAGE_LAST = 0x6ULL << DECT_PT_HDR_LENGTH_SHIFT,
DECT_PT_LONG_PAGE_ALL = 0x7ULL << DECT_PT_HDR_LENGTH_SHIFT,
};
/* zero and short page B_S channel data */
#define DECT_PT_SZP_BS_DATA_MASK 0x0fffff0000000000ULL
#define DECT_PT_SZP_BS_DATA_SHIFT 40
#define DECT_PT_SZP_BS_DATA_SIZE 3
/* long and full page B_S channel data */
#define DECT_PT_LFP_BS_DATA_MASK 0x0fffffffff000000ULL
#define DECT_PT_LFP_BS_DATA_SHIFT 24
#define DECT_PT_LFP_BS_DATA_SIZE 5
struct dect_page {
bool extend;
enum dect_page_lengths length;
};
/* MAC layer information */
#define DECT_PT_INFO_TYPE_MASK 0x000000f000000000ULL
#define DECT_PT_INFO_TYPE_SHIFT 36
#define DECT_PT_INFO_TYPE_SIZE 2
/**
* @DECT_PT_IT_FILL_BITS_OR_BLIND_LONG_SLOTS: fill bits/blind long slots if bit 47 set
* @DECT_PT_IT_BLIND_FULL_SLOT: blind full slot information
* @DECT_PT_IT_OTHER_BEARER:
* @DECT_PT_IT_RECOMMENDED_OTHER_BEARER:
* @DECT_PT_IT_GOOD_RFP_BEARER:
* @DECT_PT_IT_DUMMY_OR_CL_BEARER_POSITION:
* @DECT_PT_IT_RFP_IDENTITY:
* @DECT_PT_IT_ESCAPE:
* @DECT_PT_IT_DUMMY_OR_CL_BEARER_MARKER:
* @DECT_PT_IT_BEARER_HANDOVER_INFO:
* @DECT_PT_IT_RFP_STATUS:
* @DECT_PT_IT_ACTIVE_CARRIERS:
* @DECT_PT_IT_CL_BEARER_POSITION:
* @DECT_PT_IT_RECOMMENDED_POWER_LEVEL:
* @DECT_PT_IT_BLIND_DOUBLE_SLOT:
* @DECT_PT_IT_BLIND_FULL_SLOT_PACKET_MODE:
*
*/
enum dect_pt_info_types {
DECT_PT_IT_FILL_BITS_OR_BLIND_LONG_SLOTS= 0x0ULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_BLIND_FULL_SLOT = 0x1ULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_OTHER_BEARER = 0x2ULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_RECOMMENDED_OTHER_BEARER = 0x3ULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_GOOD_RFP_BEARER = 0x4ULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_DUMMY_OR_CL_BEARER_POSITION = 0x5ULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_RFP_IDENTITY = 0x6ULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_ESCAPE = 0x7ULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_DUMMY_OR_CL_BEARER_MARKER = 0x8ULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_BEARER_HANDOVER_INFO = 0x9ULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_RFP_STATUS = 0xaULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_ACTIVE_CARRIERS = 0xbULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_CL_BEARER_POSITION = 0xcULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_RECOMMENDED_POWER_LEVEL = 0xdULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_BLIND_DOUBLE_SLOT = 0xeULL << DECT_PT_INFO_TYPE_SHIFT,
DECT_PT_IT_BLIND_FULL_SLOT_PACKET_MODE = 0xfULL << DECT_PT_INFO_TYPE_SHIFT,
};
/* blind full slot information */
#define DECT_PT_BFS_MASK 0x0000000fff000000ULL
#define DECT_PT_BFS_SHIFT 24
struct dect_bfs {
struct dect_page page;
u16 mask;
};
/* Bearer description */
#define DECT_PT_BEARER_SN_MASK 0x0000000f00000000ULL
#define DECT_PT_BEARER_SN_SHIFT 32
#define DECT_PT_BEARER_SP_MASK 0x00000000c0000000ULL
#define DECT_PT_BEARER_SP_SHIFT 30
#define DECT_PT_BEARER_CN_MASK 0x000000003f000000ULL
#define DECT_PT_BEARER_CN_SHIFT 24
struct dect_bearer_desc {
struct dect_page page;
enum dect_pt_info_types bt;
u8 sn;
u8 sp;
u8 cn;
};
/* RFP identity */
#define DECT_PT_RFP_ID_MASK 0x0000000fff000000ULL
#define DECT_PT_RFP_ID_SHIFT 24
struct dect_rfp_id {
struct dect_page page;
u16 id;
};
/* RFP status */
#define DECT_PT_RFPS_RFP_BUSY_FLAG 0x0000000100000000ULL
#define DECT_PT_RFPS_SYS_BUSY_FLAG 0x0000000200000000ULL
struct dect_rfp_status {
struct dect_page page;
bool rfp_busy;
bool sys_busy;
};
/* Active carriers */
#define DECT_PT_ACTIVE_CARRIERS_MASK 0x0000000ffc000000ULL
#define DECT_PT_ACTIVE_CARRIERS_SHIFT 26
struct dect_active_carriers {
struct dect_page page;
u16 active;
};
/*
* MAC control (M-channel)
*/
#define DECT_MT_FRAME_RATE 2
#define DECT_MT_HDR_MASK 0xf000000000000000ULL
#define DECT_MT_HDR_SHIFT 60
#define DECT_MT_CMD_MASK 0x0f00000000000000ULL
#define DECT_MT_CMD_SHIFT 56
/**
*
*/
enum dect_mt_hdr_type {
DECT_MT_BASIC_CCTRL = 0x0ULL << DECT_MT_HDR_SHIFT,
DECT_MT_ADV_CCTRL = 0x1ULL << DECT_MT_HDR_SHIFT,
DECT_MT_MAC_TEST = 0x2ULL << DECT_MT_HDR_SHIFT,
DECT_MT_QUALITY_CTRL = 0x3ULL << DECT_MT_HDR_SHIFT,
DECT_MT_BRD_CL_SERVICE = 0x4ULL << DECT_MT_HDR_SHIFT,
DECT_MT_ENC_CTRL = 0x5ULL << DECT_MT_HDR_SHIFT,
DECT_MT_XYZ = 0x6ULL << DECT_MT_HDR_SHIFT,
DECT_MT_ESC = 0x7ULL << DECT_MT_HDR_SHIFT,
DECT_MT_TARI = 0x8ULL << DECT_MT_HDR_SHIFT,
DECT_MT_REP_CCTRL = 0x9ULL << DECT_MT_HDR_SHIFT,
};
/* basic connection control */
enum dect_basic_cctrl_cmds {
DECT_BASIC_CCTRL_ACCESS_REQ = 0x0ULL << DECT_MT_CMD_SHIFT,
DECT_BASIC_CCTRL_BEARER_HO_REQ = 0x1ULL << DECT_MT_CMD_SHIFT,
DECT_BASIC_CCTRL_CONNECTION_HO_REQ = 0x2ULL << DECT_MT_CMD_SHIFT,
DECT_BASIC_CCTRL_UNCONFIRMED_ACCESS_REQ = 0x3ULL << DECT_MT_CMD_SHIFT,
DECT_BASIC_CCTRL_BEARER_CONFIRM = 0x4ULL << DECT_MT_CMD_SHIFT,
DECT_BASIC_CCTRL_WAIT = 0x5ULL << DECT_MT_CMD_SHIFT,
DECT_BASIC_CCTRL_RELEASE = 0xfULL << DECT_MT_CMD_SHIFT,
};
#define DECT_MT_BCCTRL_FMID_MASK 0x00fff00000000000ULL
#define DECT_MT_BCCTRL_FMID_SHIFT 44
#define DECT_MT_BCCTRL_PMID_MASK 0x00000fffff000000ULL
#define DECT_MT_BCCTRL_PMID_SHIFT 24
struct dect_bcctrl {
enum dect_basic_cctrl_cmds cmd;
u16 fmid;
u32 pmid;
};
/* marker for T-MUX exceptions */
#define DECT_MT_HIGH_PRIORITY 0x1
/*
* C_T data
*/
#define DECT_C_S_SDU_SIZE 5
struct dect_ct_data {
bool pkt_0;
};
/*
* Flat representation of tail message contents
*/
enum dect_tail_msg_types {
DECT_TM_TYPE_INVALID,
DECT_TM_TYPE_ID,
DECT_TM_TYPE_SSI,
DECT_TM_TYPE_ERFC,
DECT_TM_TYPE_FPC,
DECT_TM_TYPE_EFPC,
DECT_TM_TYPE_SARI,
DECT_TM_TYPE_MFN,
DECT_TM_TYPE_PAGE,
DECT_TM_TYPE_BFS,
DECT_TM_TYPE_BD,
DECT_TM_TYPE_RFP_ID,
DECT_TM_TYPE_RFP_STATUS,
DECT_TM_TYPE_ACTIVE_CARRIERS,
DECT_TM_TYPE_BCCTRL,
DECT_TM_TYPE_CT,
};
struct dect_tail_msg {
enum dect_tail_identifications ti;
enum dect_tail_msg_types type;
union {
struct dect_idi idi;
struct dect_ssi ssi;
struct dect_erfc erfc;
struct dect_fpc fpc;
struct dect_efpc efpc;
struct dect_sari sari;
struct dect_mfn mfn;
struct dect_page page;
struct dect_bfs bfs;
struct dect_bearer_desc bd;
struct dect_rfp_id rfp_id;
struct dect_rfp_status rfp_status;
struct dect_active_carriers active_carriers;
struct dect_bcctrl bctl;
struct dect_ct_data ctd;
};
};
struct dect_si {
u32 mask;
struct dect_ssi ssi;
struct dect_erfc erfc;
struct dect_fpc fpc;
struct dect_efpc efpc;
struct dect_sari sari[DECT_SARI_CYCLE_MAX];
struct dect_mfn mfn;
u8 num_saris;
};
/*
* B-Field
*/
#define DECT_B_FIELD_SIZE 40
/**
* dect_b_identitifications - MAC layer B-Field Identification
*
* @DECT_BI_UTYPE_0: U-Type, I_N, SI_N, SI_P or I_P packet number 0
* @DECT_BI_UTYPE_1: U-Type, I_P error detect or I_P packet number 1
* @DECT_BI_ETYPE_CF_0: E-Type, all C_F or CL_F, packet number 0
* @DECT_BI_ETYPE_CF_1: E-Type, all C_F, packet number 1
* @DECT_BI_ETYPE_MAC: E-Type, all MAC control (unnumbered)
* @DECT_BI_NONE: no B-Field
*/
enum dect_b_identifications {
DECT_BI_UTYPE_0 = 0x0 << DECT_HDR_BA_SHIFT,
DECT_BI_UTYPE_1 = 0x1 << DECT_HDR_BA_SHIFT,
DECT_BI_ETYPE_CF_0 = 0x2 << DECT_HDR_BA_SHIFT,
DECT_BI_ETYPE_CF_1 = 0x3 << DECT_HDR_BA_SHIFT,
DECT_BI_ETYPE_MAC = 0x6 << DECT_HDR_BA_SHIFT,
DECT_BI_NONE = 0x7 << DECT_HDR_BA_SHIFT,
};
struct dect_skb_b_cb {
enum dect_b_identifications id;
};
#define DECT_B_CB(skb) ((struct dect_skb_b_cb *)(skb)->cb)
#define DECT_C_F_SDU_SIZE 8
#define DECT_G_F_SDU_SIZE 8
/**
* enum dect_mac_channels - internal MAC control channels
*
* @DECT_MC_Q: System information and multiframe marker
* @DECT_MC_N: Identities information
* @DECT_MC_M: MAC control channel
* @DECT_MC_P: MAC Paging channel
*/
enum dect_mac_channels {
DECT_MC_Q,
DECT_MC_N,
DECT_MC_M,
DECT_MC_P,
};
/**
* enum dect_data_channels - logical MAC data channels
*
* @DECT_MC_G_F:
* @DECT_MC_C_S: Higher layer C-Plane channel (slow)
* @DECT_MC_C_F: Higher layer C-Plane channel (fast)
* @DECT_MC_I_N: Higher layer U-Plane channel (numbered)
* @DECT_MC_I_P: Higher layer U-Plane channel (protected)
* @DECT_MC_SI_N: Higher layer connectionless U-Plane channel (numbered)
* @DECT_MC_SI_P: Higher layer connectionless U-Plane channel (protected)
*/
enum dect_data_channels {
DECT_MC_G_F,
DECT_MC_C_S,
DECT_MC_C_F,
DECT_MC_I_N,
DECT_MC_I_P,
DECT_MC_SI_N,
DECT_MC_SI_P,
__DECT_MC_MAX
};
#define DECT_MC_MAX (__DECT_MC_MAX - 1)
/**
* enum dect_mac_connection_types - MAC Connection types
*
* @DECT_MAC_CONN_BASIC: Basic connection, always I_N_min_delay service
* @DECT_MAC_CONN_ADV: Advanced connection
* @DECT_MAC_CONN_COMPLEMENT: Complementary connection
*/
enum dect_mac_connection_types {
DECT_MAC_CONN_BASIC,
DECT_MAC_CONN_ADV,
DECT_MAC_CONN_COMPLEMENT,
};
enum dect_mac_service_types {
DECT_SERVICE_IN_MIN_DELAY,
DECT_SERVICE_IN_NORM_DELAY,
DECT_SERVICE_IP_ERROR_DETECTION,
DECT_SERVICE_IP_ERROR_CORRECTION,
DECT_SERVICE_U_PLANE_UNKNOWN,
DECT_SERVICE_C_ONLY,
DECT_SERVICE_IPQ_ERROR_DETECTION,
DECT_SERVICE_IPQ_ERROR_CORRECTION,
};
/**
* struct dect_mbc_id
*
* @mcei: MAC Connection Endpoint Identifier
* @type: Connection Type (Basic/Advanced)
* @ari: FT identifier
* @pmid: Portable MAC Identity
* @ecn: Exchanged Connection Number
* @service: Service type
*/
struct dect_mbc_id {
u32 mcei;
enum dect_mac_connection_types type;
struct dect_ari ari;
struct dect_pmid pmid;
u8 ecn;
enum dect_mac_service_types service;
};
#endif /* _NET_DECT_MAC_H */

166
include/net/dect/mac_ccf.h Normal file
View File

@ -0,0 +1,166 @@
/*
* DECT MAC Layer - Cluster Control Functions (CCF)
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*/
#ifndef _NET_DECT_MAC_CCF_H
#define _NET_DECT_MAC_CCF_H
#include <linux/skbuff.h>
#include <net/dect/mac.h>
/**
* struct dect_bmc_skb_cb
*
* @fast: fast page
* @stamp: multiframe number at time of TX request
* @repetitions: number of page repetitions
*/
struct dect_bmc_skb_cb {
bool fast;
u32 stamp;
u8 repetitions;
};
#define DECT_BMC_CB(skb) ((struct dect_bmc_skb_cb *)(skb)->cb)
#define DECT_PAGE_LIFETIME 6 /* multiframes */
/**
* struct dect_bmc - broadcast message control
*
* @bcs: broadcast controller list
* @index: system information round robin index
*/
struct dect_bmc {
struct list_head bcs;
unsigned int index;
};
struct dect_cmc {
};
enum dect_mbc_state {
DECT_MBC_NONE,
DECT_MBC_INITIATED,
DECT_MBC_ESTABLISHED,
};
/**
* struct dect_mbc - DECT Multi-Bearer Control
*
* @list: Cluster connection list node
* @cl: Cluster the MBC is contained in
* @type: connection type
* @id: MBC identity
* @state: MBC state
* @timer: Connection setup timer (T200)
* @ch: Cell handling associated traffic bearer
* @setup_cnt: number of setup attempts (N200)
* @c_tx_queue: C-channel TX-queue
* @i_tx_queue: I-channel TX-queue
* @gf_tx_queue: G_F-channel TX-queue
* @cs_rx_seq: C_S receive sequence number
* @cs_tx_seq: C_S transmit sequence number
*/
struct dect_mbc {
struct list_head list;
struct dect_cluster *cl;
enum dect_mac_connection_types type;
struct dect_mbc_id id;
enum dect_mbc_state state;
struct timer_list timer;
const struct dect_cell_handle *ch;
u8 setup_cnt;
struct sk_buff_head c_tx_queue;
struct sk_buff_head i_tx_queue;
struct sk_buff_head gf_tx_queue;
u8 cs_rx_seq;
u8 cs_tx_seq;
};
#define DECT_MBC_SETUP_TIMEOUT (5 * HZ) /* seconds */
#define DECT_MBC_SETUP_MAX_ATTEMPTS 10
extern u32 dect_mbc_alloc_mcei(struct dect_cluster *cl);
extern int dect_mbc_con_request(struct dect_cluster *cl,
const struct dect_mbc_id *id);
extern void dect_bmc_mac_page_request(struct dect_cluster *cl,
struct sk_buff *skb, bool expedited);
struct dect_llme_req;
extern int dect_cluster_scan(struct dect_cluster *cl,
const struct dect_llme_req *lreq,
const struct dect_ari *pari,
const struct dect_ari *pari_mask);
/**
* struct dect_ccf_ops - Cluster Control Ops
*
* @bind: bind cell to cluster
* @unbind: unbind cell from cluster
* @mac_info_indicate: indicate FP mac layer information (PP only)
* @mbc_conn_indicate: indicate a new TBC connection
* @mbc_conn_notify: notify MBC of TBC events
* @mbc_data_indicate: indicate new data to MBC
* @mbc_dtr_indicate: indicate data transmit ready to MBC
* @bmc_page_indicate: indicate reception of a page message to the BMC
*/
struct dect_cluster_handle;
struct dect_scan_result;
enum dect_tbc_event;
struct dect_ccf_ops {
int (*bind)(struct dect_cluster_handle *,
struct dect_cell_handle *);
void (*unbind)(struct dect_cluster_handle *,
struct dect_cell_handle *);
void (*scan_report)(const struct dect_cluster_handle *,
const struct dect_scan_result *);
void (*mac_info_indicate)(const struct dect_cluster_handle *,
const struct dect_idi *,
const struct dect_si *);
int (*mbc_conn_indicate)(const struct dect_cluster_handle *,
const struct dect_cell_handle *,
const struct dect_mbc_id *);
int (*mbc_conn_notify)(const struct dect_cluster_handle *,
const struct dect_mbc_id *,
enum dect_tbc_event);
void (*mbc_data_indicate)(const struct dect_cluster_handle *,
const struct dect_mbc_id *,
enum dect_data_channels chan,
struct sk_buff *);
void (*mbc_dtr_indicate)(const struct dect_cluster_handle *,
const struct dect_mbc_id *,
enum dect_data_channels chan);
void (*bmc_page_indicate)(const struct dect_cluster_handle *,
struct sk_buff *);
};
/**
* struct dect_cluster_handle - Cell's view of a cluster
*
* @ops: Cluster Control Function ops
* @index: Cluster index
* @tipc_id: Cluster TIPC user ID
* @tportref: Topology Service port reference (remote cluster only)
* @portref: Cell Control Protocol port reference (remote cluster only)
*/
struct dect_cluster_handle {
const struct dect_ccf_ops *ops;
u8 index;
u32 tipc_id;
u32 tportref;
u32 portref;
};
#endif /* _NET_DECT_MAC_CCF_H */

556
include/net/dect/mac_csf.h Normal file
View File

@ -0,0 +1,556 @@
/*
* DECT MAC Layer - Cell Site Functions (CSF)
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*/
#ifndef _NET_DECT_MAC_CSF_H
#define _NET_DECT_MAC_CSF_H
#include <net/dect/mac.h>
#include <net/dect/transceiver.h>
/**
* enum dect_timer_bases - timer bases for DECT timers
*
* @DECT_TIMER_RX: receive time base
* @DECT_TIMER_TX: send time base
*/
enum dect_timer_bases {
DECT_TIMER_RX,
DECT_TIMER_TX,
__DECT_TIMER_BASE_MAX
};
#define DECT_TIMER_BASE_MAX (__DECT_TIMER_BASE_MAX - 1)
/**
* struct dect_timer_base - timer base
*
* @timers: list of active timers
* @slot: slot position
* @framenum: frame number
* @mfn: multiframe number
*/
struct dect_timer_base {
struct list_head timers;
u8 slot;
u8 framenum;
u32 mfn;
};
/**
* struct dect_timer - DECT TDMA frame timer
*
* @list: timer list node
* @base: timer base
* @mfn: expiration time: multiframe number
* @frame: expiration time: frame number
* @slot: expiration time: slot number
* @func: timer function
* @data: timer data
*/
struct dect_timer {
struct list_head list;
enum dect_timer_bases base;
u32 mfn;
u8 frame;
u8 slot;
void (*func)(struct dect_cell *, void *);
void *data;
};
#define DECT_CHANNEL_LIST_DBM_RES 6
#define DECT_CHANNEL_LIST_BINS (DECT_RSSI_DBM_RANGE / DECT_CHANNEL_LIST_DBM_RES)
/**
* struct dect_channel_list_entry
*
* @list: channel list bin node
* @slot: slot number
* @carrier: RF-carrier
* @rssi: measured RSSI value
*/
struct dect_channel_list_entry {
struct list_head list;
u8 slot;
u8 carrier;
u8 rssi;
};
/**
* struct dect_channel_list - Basic channel list
*
* @list: cell's channel lists list node
* @pkt: packet type used for RSSI measurement
* @status: bitmask of completed carriers
* @timer: update timer
* @available: number of available entries
* @bins: channels ordered by RSSI value
* @entries: channel list entries
*
* A channel list contains channel descriptions of all physical channels
* able to carry the packet type, sorted into multiple bins based on the
* maximum RSSI value of the TDD slot pair.
*/
struct dect_channel_list {
struct list_head list;
enum dect_packet_types pkt;
u64 status;
struct dect_timer timer;
u16 available;
struct list_head bins[DECT_CHANNEL_LIST_BINS];
struct dect_channel_list_entry entries[];
};
#define DECT_CHANNEL_LIST_MAX_AGE 30 /* T209: 30 seconds */
#define DECT_CHANNEL_LIST_MAX_DBM -50 /* dBm */
#define DECT_CHANNEL_LIST_LOW_WATERMARK 20 /* channels */
/**
* enum dect_bearer_types
*
* @DECT_SIMPLEX_BEARER: simplex bearer, one physical channel
* @DECT_DUPLEX_BEARER: two simplex bearers on opposite channels
* @DECT_DOUBLE_SIMLEX_BEARER: two simplex bearers in same direction
* @DECT_DOUBLE_DUPLEX_BEARER: two duplex bearers
*/
enum dect_bearer_types {
DECT_SIMPLEX_BEARER,
DECT_DUPLEX_BEARER,
DECT_DOUBLE_SIMPLEX_BEARER,
DECT_DOUBLE_DUPLEX_BEARER,
};
enum dect_bearer_states {
DECT_DUMMY_BEARER,
DECT_TRAFFIC_BEARER,
DECT_CL_BEARER,
};
enum dect_bearer_modes {
DECT_BEARER_RX,
DECT_BEARER_TX,
};
/**
* enum dect_bearer_state - DECT MAC bearer states
*
* @DECT_BEARER_INACTIVE: bearer inactive
* @DECT_BEARER_SCHEDULED: bearer is scheduled for activation
* @DECT_BEARER_RSSI_CONFIRM: bearer is scheduled for RSSI confirmation
* @DECT_BEARER_RSSI_CONFIRMED: RSSI is confirmed, bearer is scheduled for e
* @DECT_BEARER_ENABLED: bearer is enabled
*/
enum dect_bearer_state {
DECT_BEARER_INACTIVE,
DECT_BEARER_SCHEDULED,
DECT_BEARER_RSSI_CONFIRM,
DECT_BEARER_RSSI_CONFIRMED,
DECT_BEARER_ENABLED,
};
struct dect_bearer;
struct dect_bearer_ops {
enum dect_bearer_states state;
void (*enable)(struct dect_cell *, struct dect_bearer *);
void (*report_rssi)(struct dect_cell *, struct dect_bearer *,
u8 slot, u8 rssi);
void (*rcv)(struct dect_cell *cell, struct dect_bearer *,
struct sk_buff *);
};
/**
* struct dect_bearer - DECT MAC Bearer
*
* @type: bearer type
* @state: operational state
* @trx: DECT transceiver
* @chd: channel description
* @mode: bearer mode (RX/TX)
* @tx_timer: TX enable timer
* @rssi: last measured RSSI of selected channel
* @m_tx_queue: M-channel TX queue
* @q: Hdr-field MUX for Q1/Q2 bit settings
* @union: bearer type specific data
*/
struct dect_bearer {
enum dect_bearer_types type;
const struct dect_bearer_ops *ops;
struct dect_transceiver *trx;
struct dect_channel_desc chd;
enum dect_bearer_modes mode;
enum dect_bearer_state state;
struct dect_timer tx_timer;
u8 rssi;
struct sk_buff_head m_tx_queue;
u8 q;
union {
struct dect_dbc *dbc;
struct dect_cbc *cbc;
struct dect_tbc *tbc;
struct dect_irc *irc;
void *data;
};
};
/**
* struct dect_bc - broadcast controller
*
* @list: broadcast message control BC list node
* @p_rx_skb: current RX P-channel message
*/
struct dect_bc {
struct list_head list;
struct sk_buff *p_rx_skb;
};
/**
* struct dect_dbc - dummy bearer control
*
* @list: cell dbc list node
* @cell: DECT cell
* @bearer: dummy bearer
* @bc: broadcast controller
*/
struct dect_dbc {
struct list_head list;
struct dect_cell *cell;
struct dect_bearer *bearer;
struct dect_bc bc;
};
/*
* struct dect_cbc - connectionless bearer control
*
* @cell: DECT cell
* @dl_bearer: connectionless downlink bearer
* @ul_bearer: connectionless uplink bearer, if present
* @bc: broadcast controller
*/
struct dect_cbc {
struct dect_cell *cell;
struct dect_bearer *dl_bearer;
struct dect_bearer *ul_bearer;
struct dect_bc bc;
};
/**
* enum dect_tbc_state - DECT Traffic Bearer Controller state
*
* @DECT_TBC_NONE: Initial state
* @DECT_TBC_REQ_SENT: Initiator: bearer request sent
* @DECT_TBC_WAIT_RCVD: Initiator: intermediate state
* @DECT_TBC_CONFIRM_WAIT: Initiator: waiting for confirmation
* @DECT_TBC_REQ_RCVD: Responder: request received
* @DECT_TBC_RESPONSE_SENT: Responder: immediate response to request sent
* @DECT_TBC_OTHER_WAIT: Waiting for "other" message
* @DECT_TBC_ESTABLISHED Established
* @DECT_TBC_RELEASING First RELEASE message sent
* @DECT_TBC_RELEASED: Second RELEASE message sent
*/
enum dect_tbc_state {
DECT_TBC_NONE,
DECT_TBC_REQ_SENT,
DECT_TBC_WAIT_RCVD,
DECT_TBC_REQ_RCVD,
DECT_TBC_RESPONSE_SENT,
DECT_TBC_OTHER_WAIT,
DECT_TBC_ESTABLISHED,
DECT_TBC_RELEASING,
DECT_TBC_RELEASED,
};
/**
* enum dect_tbc_event - DECT Traffic Bearer events
*
* @DECT_TBC_SETUP_FAILED: Bearer setup failed
* @DECT_TBC_SETUP_COMPLETE: Bearer setup complete
* @DECT_TBC_HANDSHAKE_TIMEOUT: RFPI handshake timeout
* @DECT_TBC_REMOTE_RELEASE: Release procedure initiated by remote side
*/
enum dect_tbc_event {
DECT_TBC_SETUP_FAILED,
DECT_TBC_SETUP_COMPLETE,
DECT_TBC_HANDSHAKE_TIMEOUT,
DECT_TBC_REMOTE_RELEASE,
};
/**
* struct dect_tbc - DECT Traffic Bearer Control
*
* @list: device TBC list node
* @cell: DECT cell
* @id: ID of associated MBC
* @txb: TX bearer
* @rxb: RX bearer
* @state: Bearer establishment state
* @tx_timer: Transmit activation timer
* @wd_timer: Receive watchdog timer
* @release_timer: Release timer for unacknowledged release procedure
* @normal_tx_timer: Normal transmit timer for C-channel/I_N normal delay transmission
* @tx_timer: Minimum delay transmit timer
* @c_tx_skb: C_S segment for next TDMA frame
* @c_tx_pkt: C_S segment sequence number
* @b_tx_skb: B-field data segment for next TDMA frame
* @bc: Broadcast Control
*/
struct dect_tbc {
struct list_head list;
struct dect_cell *cell;
struct dect_mbc_id id;
struct dect_bearer *txb;
struct dect_bearer *rxb;
enum dect_tbc_state state;
struct dect_timer wait_timer;
struct dect_timer wd_timer;
struct dect_timer release_timer;
struct dect_timer normal_tx_timer;
struct dect_timer tx_timer;
uint8_t c_tx_pkt;
struct sk_buff *c_tx_skb;
struct sk_buff *b_tx_skb;
struct dect_bc bc;
};
#define DECT_TBC_RFPI_TIMEOUT (5 * DECT_FRAMES_PER_SECOND)
enum dect_scan_status {
DECT_SCAN_FAIL,
DECT_SCAN_TIMEOUT,
DECT_SCAN_COMPLETE,
};
/**
* struct dect_irc - Idle receiver control
*
* @cell: DECT cell
* @trx: DECT transceiver
* @ari: ARI filter
* @ari_mask: ARI filter mask
* @idi: identities information
* @si: system information
* @notify: notification callback
* @rx_scn: Scan carrier number (RX time base)
* @tx_scn: Scan carrier number (TX time base)
* @rx_frame_timer: rx_scn update timer
* @tx_frame_timer: tx_scn update timer
*/
struct dect_irc {
struct dect_cell *cell;
struct dect_transceiver *trx;
struct dect_llme_req lreq;
struct dect_ari ari;
struct dect_ari ari_mask;
u16 timeout;
u16 rssi;
struct dect_idi idi;
struct dect_si si;
void (*notify)(struct dect_cell *,
struct dect_transceiver *,
enum dect_scan_status);
u8 rx_scn;
u8 tx_scn;
struct dect_timer rx_frame_timer;
struct dect_timer tx_frame_timer;
struct dect_bearer scan_bearer;
};
#define DECT_IRC_SCN_OFF 3
struct dect_scan_result {
struct dect_llme_req lreq;
struct dect_idi idi;
struct dect_si si;
u8 rssi;
};
/**
* struct dect_csf_ops - Cell Site Function ops
*
* @set_mode: set cell to PP/FP mode
* @scan: initiate scan for pari/pari_mask
* @preload: preload system information
* @enable: enable cell
* @page_request: deliver paging message
* @tbc_initiate: initiate a new connection
* @tbc_confirm: confirm an incoming connection
* @tbc_release: release a TBC
*
* The CSF ops define the interface in the direction CCF -> CSF.
*/
struct dect_cell_handle;
struct dect_csf_ops {
int (*set_mode)(const struct dect_cell_handle *,
enum dect_cluster_modes);
int (*scan)(const struct dect_cell_handle *,
const struct dect_llme_req *lreq,
const struct dect_ari *, const struct dect_ari *);
int (*preload)(const struct dect_cell_handle *,
const struct dect_ari *, u8,
const struct dect_si *);
int (*enable)(const struct dect_cell_handle *);
void (*page_request)(const struct dect_cell_handle *,
struct sk_buff *);
int (*tbc_initiate)(const struct dect_cell_handle *,
const struct dect_mbc_id *,
const struct dect_channel_desc *);
int (*tbc_confirm)(const struct dect_cell_handle *,
const struct dect_mbc_id *);
void (*tbc_release)(const struct dect_cell_handle *,
const struct dect_mbc_id *);
void (*tbc_data_request)(const struct dect_cell_handle *,
const struct dect_mbc_id *,
enum dect_data_channels chan,
struct sk_buff *);
};
/**
* struct dect_cell_handle - DECT cluster view of a cell
*
* @list: cluster cell list node
* @clh: bound cluster handle
* @ops: cell site function ops
* @rpn: assigned radio part number
* @portref: cell control protocol port reference (remote cells)
*/
struct dect_cell_handle {
struct list_head list;
struct dect_cluster_handle *clh;
const struct dect_csf_ops *ops;
u8 rpn;
u32 portref;
};
enum dect_cell_states {
DECT_CELL_ENABLED = 1 << 0,
};
/**
* struct dect_cell - DECT cell: one radio system
*
* @list: cell list node
* @name: cells' name
* @index: unique numeric cell identifier
* @flags: operational and status flags
* @handle: cell handle
* @lock: lock
* @mode: operational mode (FP/PP)
* @state: bitmask of enum dect_cell_states
* @idi: FP System Identity
* @fmid: FMID (Fixed MAC IDentity)
* @si: FP System Information
* @bcs: Broadcast Controllers
* @cbc: Connectionless Bearer Controller
* @dbcs: Dummy Bearer Controllers
* @tbcs: list of Traffic Bearer Controllers
* @chanlists: list of channel lists for different channel types
* @timer_base: RX/TX timer bases
* @trg: DECT transceiver group
*/
struct dect_cell {
struct list_head list;
char name[DECTNAMSIZ];
u32 index;
u32 flags;
struct dect_cell_handle handle;
spinlock_t lock;
enum dect_cluster_modes mode;
u32 state;
/* identities */
struct dect_idi idi;
u16 fmid;
/* system information */
struct dect_si si;
u32 blind_full_slots;
/* Broadcast controllers and related data */
struct dect_timer page_timer;
struct sk_buff_head page_queue;
struct sk_buff_head page_fast_queue;
struct sk_buff *page_sdu;
struct sk_buff_head page_tx_queue;
struct list_head bcs;
unsigned int si_idx;
struct dect_cbc cbc;
struct list_head dbcs;
struct list_head tbcs;
/* channel lists */
struct list_head chl_pending;
struct list_head chanlists;
struct dect_channel_list *chl_next;
struct dect_channel_list *chl;
struct dect_timer_base timer_base[DECT_TIMER_BASE_MAX + 1];
struct dect_transceiver_group trg;
};
static inline u8 dect_normal_transmit_base(const struct dect_cell *cell)
{
return cell->mode == DECT_MODE_FP ? 0 : DECT_HALF_FRAME_SIZE;
}
static inline u8 dect_normal_receive_base(const struct dect_cell *cell)
{
return cell->mode == DECT_MODE_FP ? DECT_HALF_FRAME_SIZE : 0;
}
#define dect_foreach_transmit_slot(slot, end, cell) \
for ((slot) = dect_normal_transmit_base(cell), \
(end) = (slot) + DECT_HALF_FRAME_SIZE; \
(slot) < (end); (slot)++)
#define dect_foreach_receive_slot(slot, end, cell) \
for ((slot) = dect_normal_receive_base(cell), \
(end) = (slot) + DECT_HALF_FRAME_SIZE; \
(slot) < (end); (slot)++)
extern struct dect_cell *dect_cell_get_by_index(u32 index);
extern void dect_cell_init(struct dect_cell *cell);
extern int dect_cell_bind(struct dect_cell *cell, u8 index);
extern void dect_cell_shutdown(struct dect_cell *cell);
extern int dect_cell_attach_transceiver(struct dect_cell *cell,
struct dect_transceiver *trx);
extern void dect_cell_detach_transceiver(struct dect_cell *cell,
struct dect_transceiver *trx);
extern void dect_mac_rcv(struct dect_transceiver *trx,
struct dect_transceiver_slot *ts,
struct sk_buff *skb);
extern void dect_mac_report_rssi(struct dect_transceiver *trx,
struct dect_transceiver_slot *ts, u8 rssi);
extern void dect_mac_rx_tick(struct dect_transceiver_group *grp, u8 slot);
extern void dect_mac_tx_tick(struct dect_transceiver_group *grp, u8 slot);
extern void dect_mac_irc_rcv(struct dect_transceiver *trx, struct sk_buff *skb);
extern void dect_mac_irc_tick(struct dect_transceiver *trx);
#endif /* _NET_DECT_MAC_CSF_H */

View File

@ -0,0 +1,633 @@
/*
* DECT Transceiver Layer
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*/
#ifndef _NET_DECT_TRANSCEIVER_H
#define _NET_DECT_TRANSCEIVER_H
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/dect.h>
#include <linux/dect_netlink.h>
#define DECT_RSSI_RANGE 255
#define DECT_RSSI_DBM_LOW -93
#define DECT_RSSI_DBM_RANGE 60
static inline u8 dect_dbm_to_rssi_rel(s8 dbm)
{
return dbm * DECT_RSSI_RANGE / DECT_RSSI_DBM_RANGE;
}
static inline u8 dect_dbm_to_rssi(s8 dbm)
{
return dect_dbm_to_rssi_rel(dbm - DECT_RSSI_DBM_LOW);
}
#define DECT_RSSI_AVG_SCALE 3
static inline u16 dect_average_rssi(u16 cur, u16 sample)
{
if (cur == 0)
cur = sample << DECT_RSSI_AVG_SCALE;
else {
cur -= cur >> DECT_RSSI_AVG_SCALE;
cur += sample;
}
return cur;
}
#define DECT_CARRIER_NUM 64
static inline u8 dect_next_carrier(u64 rfcars, u8 carrier)
{
u64 tmp;
if (WARN_ON(rfcars == 0))
return 0;
tmp = rfcars & ~((1ULL << (carrier + 1)) - 1);
if (tmp == 0)
tmp = rfcars;
return ffs(tmp) - 1;
}
static inline u8 dect_prev_carrier(u64 rfcars, u8 carrier)
{
u64 tmp;
if (WARN_ON(rfcars == 0))
return 0;
tmp = rfcars & ((1ULL << carrier) - 1);
if (tmp == 0)
tmp = rfcars;
return fls(tmp) - 1;
}
static inline u8 dect_carrier_sub(u64 rfcars, u8 carrier, u8 n)
{
while (n != 0) {
carrier = dect_prev_carrier(rfcars, carrier);
n--;
}
return carrier;
}
static inline u8 dect_carrier_distance(u64 rfcars, u8 from, u8 to)
{
if (from >= to) {
/* clear bits between to and from */
rfcars &= ~(((1ULL << (from - to)) - 1) << to);
} else {
/* clear bits not between from and to */
rfcars &= ((1ULL << (to - from)) - 1) << from;
}
return hweight64(rfcars);
}
#define DECT_BAND_NUM 32
#define DECT_DEFAULT_BAND 0
#define DECT_FREQUENCY_F0 1897344 /* kHz */
#define DECT_CARRIER_WIDTH 1728 /* kHz */
/**
* struct dect_band - DECT RF-band
*
* @band: RF-band number
* @carriers: number of defined carriers
* @frequency: frequency of each carrier in kHz
*/
struct dect_band {
u8 band;
u8 carriers;
u32 frequency[];
};
#define DECT_FRAME_SIZE 24
#define DECT_HALF_FRAME_SIZE (DECT_FRAME_SIZE / 2)
#define DECT_FRAMES_PER_SECOND 100
#define DECT_SCAN_SLOT 0
#define DECT_SLOT_MASK 0x00ffffff
static inline u8 dect_next_slotnum(u8 slot)
{
if (++slot == DECT_FRAME_SIZE)
slot = 0;
return slot;
}
static inline u8 dect_slot_add(u8 s1, u8 s2)
{
return (s1 + s2) % DECT_FRAME_SIZE;
}
static inline u8 dect_slot_distance(u8 s1, u8 s2)
{
return s2 >= s1 ? s2 - s1 : DECT_FRAME_SIZE + s2 - s1;
}
#define dect_foreach_slot(slot) \
for ((slot) = 0; (slot) < DECT_FRAME_SIZE; (slot)++)
/**
* enum dect_slot_types - DECT slot types
*
* @DECT_HALF_SLOT: Half-slot format (240 bits)
* @DECT_FULL_SLOT: Full-slot format (480 bits)
* @DECT_DOUBLE_SLOT: Double-slot format (960 bits)
*/
enum dect_slot_types {
DECT_HALF_SLOT,
DECT_FULL_SLOT,
DECT_DOUBLE_SLOT,
};
/**
* 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
*/
enum dect_packet_types {
DECT_PACKET_P00,
DECT_PACKET_P08,
DECT_PACKET_P32,
DECT_PACKET_P80,
__DECT_PACKET_MAX
};
#define DECT_PACKET_MAX (__DECT_PACKET_MAX - 1)
enum dect_packet_sizes {
DECT_P00_SIZE = 12,
DECT_P08_SIZE = 23,
DECT_P32_SIZE = 53,
DECT_P80_SIZE = 113,
};
#define DECT_PREAMBLE_SIZE 4
/**
* enum dect_b_formats - DECT B-Field formats
*
* @DECT_B_NONE: No B-field
* @DECT_B_UNPROTECTED: Unprotected B-field format
* @DECT_B_PROTECTED: Protected B-field format
*
* The B-Field format can be used by a transceiver for offloading X-CRC
* calculation.
*/
enum dect_b_formats {
DECT_B_NONE,
DECT_B_UNPROTECTED,
DECT_B_PROTECTED,
__DECT_B_MAX
};
#define DECT_B_MAX (__DECT_B_MAX - 1)
/**
* struct dect_channel_desc - DECT physical channel description
*
* @pkt: Packet type in use
* @b_fmt: B-Field format for checksum offloading
* @slot: Slot number
* @carrier: RF-carrier number
*/
struct dect_channel_desc {
enum dect_packet_types pkt;
enum dect_b_formats b_fmt;
u8 slot;
u8 carrier;
};
/**
* struct dect_transceiver_slot - Transceiver TDMA slot
*
* @state: current state
* @desc: channel description
* @bearer: associated bearer
* @rssi: averaged RSSI
* @rx_bytes: RX byte count
* @rx_packets: RX packet count
* @tx_bytes: TX byte count
* @tx_packets: TX packet count
*/
struct dect_transceiver_slot {
enum dect_slot_states state;
struct dect_channel_desc chd;
struct dect_bearer *bearer;
u16 rssi;
u32 rx_bytes;
u32 rx_packets;
u32 tx_bytes;
u32 tx_packets;
};
/**
* struct dect_transceiver_event - one atomic unit of work for the MAC layer
*
* @trx: transceiver
* @busy: synchronizer
* @list: transceiver group events list node
* @rx_queue: received packets
* @rssi: RSSI measurement in scanning slots
* @rssi_mask: RSSI measurement positions
* @slotpos: transceiver slot position in TDMA frame
*
* A transceiver operates asynchronously to the MAC layer, but the MAC layer's
* timing needs to be strictly synchronized to the receiver.
*
* This structure contains the packets from multiple consequitive slots received
* by the receiver in one unit (up to ops->eventrate frames). Slotpos specifies
* the transceivers current position in the TDMA frame (== the minimum current
* time) and is used for timing purposes and slot maintenance operations of the
* upcoming slots. A transceiver uses a fixed amount of these structure and
* synchronizes with BH processing through the busy marker. When BH processing
* is too slow, frames are dropped.
*/
struct dect_transceiver_event {
struct dect_transceiver *trx;
atomic_t busy;
struct list_head list;
struct sk_buff_head rx_queue;
u8 rssi[DECT_HALF_FRAME_SIZE / 2];
u8 rssi_mask;
u8 slotpos;
};
struct dect_skb_trx_cb {
struct dect_transceiver *trx;
u32 mfn;
u8 frame;
u8 slot;
u8 rssi;
};
static inline struct dect_skb_trx_cb *DECT_TRX_CB(const struct sk_buff *skb)
{
BUILD_BUG_ON(sizeof(struct dect_skb_trx_cb) > sizeof(skb->cb));
return (struct dect_skb_trx_cb *)skb->cb;
}
/**
* struct dect_transceiver_ops - DECT transceiver operations
*
* @disable: shut the transceiver down
* @enable: bring the transceiver to operational state
* @confirm: confirm a received signal in slave mode
* @unlock: release a confirmed signal again
* @lock: lock to a signal
* @set_mode: set the mode (RX/TX/SCANNING) for a slot
* @set_carrier: set the RF-carrier for a slot
* @set_band: set the RF-band
* @destructor: destructor
* @name transceiver driver name
* @slotmask: bitmask of available slots
* @eventrate: rate at which slot events are generated, must be integral
* divisor of the number of slots per TDMA half frame
* @latency: latency in slots until updates for a slot take effect
*
* A transceiver provides frame reception and transmission, signal strength
* measurement as well as a reference clock for the MAC layer. It can exist
* in two basic states:
*
* - master: doesn't need initial synchronization to a radio signal
* - slave: needs to synchronize timing with a signal
*
* Only the first transceiver of a FP is a master, PPs are always slaves to
* a FPs timing. Secondary and further transceivers of a FP also start as
* slaves until they have synchronized to one of the already running
* transceivers.
*
* Locking to a new signal works in multiple phases:
*
* 1) The ->enable() callback is invoked. The driver is expected to initiate a
* scan for a signal, during which it will pass on any received frame to the
* transceiver layer. As no framing has been established, all packets should
* indicate a slot number of zero.
*
* 2) While scanning for a signal, the ->set_carrier() callback may be invoked
* with a slot number of zero. The driver is expected to adjust the carrier
* on which it is scanning for a signal.
*
* 3) When the MAC layer determines interest in a received signal, the ->confirm()
* callback is invoked. The driver is expected to continue to pass frames from
* this signal to the MAC layer to establish framing.
*
* 3a) When the MAC layer is only collecting information for a scan, it may call
* the ->unlock callback to release a previously confirmed signal.
*
* 4) Once the MAC layer has determined framing relative to the slot timing, the
* ->lock() callback is invoked. At this point, only a single physical channel
* is received. The driver should synchronize the hardware to the framing to
* make it interrupt at the appropriate times.
*
*/
struct dect_transceiver;
struct dect_transceiver_ops {
void (*disable)(const struct dect_transceiver *trx);
void (*enable)(const struct dect_transceiver *trx);
void (*confirm)(const struct dect_transceiver *trx);
void (*unlock)(const struct dect_transceiver *trx);
void (*lock)(const struct dect_transceiver *trx, u8 slot);
void (*set_mode)(const struct dect_transceiver *trx,
const struct dect_channel_desc *chd,
enum dect_slot_states mode);
void (*set_carrier)(const struct dect_transceiver *trx,
u8 slot, u8 carrier);
void (*tx)(const struct dect_transceiver *trx,
struct sk_buff *skb);
u64 (*set_band)(const struct dect_transceiver *trx,
const struct dect_band *band);
void (*destructor)(struct dect_transceiver *trx);
const char *name;
u32 slotmask;
u8 eventrate;
u8 latency;
};
/**
* enum dect_transceiver_modes - Transceiver synchronization modes
*
* @DECT_TRANSCEIVER_MASTER: Transceiver determines reference time (FP)
* @DECT_TRANSCEIVER_SLAVE: Transceiver is slave to foreign reference timing
*/
enum dect_transceiver_modes {
DECT_TRANSCEIVER_MASTER,
DECT_TRANSCEIVER_SLAVE,
};
/**
* enum dect_transceiver_states - transceiver synchronization states
*
* @DECT_TRANSCEIVER_STOPPED: transceiver is inactive
* @DECT_TRANSCEIVER_UNLOCKED: transceiver is not synchronized to any RFP
* @DECT_TRANSCEIVER_LOCK_PENDING: transceiver is receiving RFP transmissions,
* but has not obtained frame synchonization
* @DECT_TRANSCEIVER_LOCKED: the transceiver has achieved frame and
* multiframe lock to an RFP
*
* These correspond to the ETS 300 175-3 Annex D PT MAC layer states, but are
* per transceiver as we also need to synchronize secondary transceivers.
*/
enum dect_transceiver_states {
DECT_TRANSCEIVER_STOPPED,
DECT_TRANSCEIVER_UNLOCKED,
DECT_TRANSCEIVER_LOCK_PENDING,
DECT_TRANSCEIVER_LOCKED,
};
/**
* struct dect_transceiver_stats - transceiver statistics
*
* @event_busy: events lost due to MAC layer busy
* @event_late: events lost due to transceiver late
*/
struct dect_transceiver_stats {
u32 event_busy;
u32 event_late;
};
/**
* struct dect_transceiver - DECT transceiver
*
* @list: transceiver list node
* @ops: transceiver ops
* @name: transceiver identity
* @stats: transceiver statistics
* @mode: synchronization mode
* @state: synchronization state
* @band: current RF-band
* @carriers: bitmask of supported carriers in the current band
* @slots: transceiver slot state
* @index: cell transceiver index
* @segno: transceiver receive sequence number
* @cell: cell the transceiver is assigned to
* @irc: idle receiver control
* @event: dynamic amount of transceiver event structures
*
* Following the event structures is the private driver data.
*/
struct dect_transceiver {
struct list_head list;
const struct dect_transceiver_ops *ops;
char name[DECTNAMSIZ];
struct dect_transceiver_stats stats;
enum dect_transceiver_modes mode;
enum dect_transceiver_states state;
const struct dect_band *band;
u64 carriers;
struct dect_transceiver_slot slots[DECT_FRAME_SIZE];
u32 blind_full_slots;
u8 index;
u32 seqno;
struct dect_cell *cell;
struct dect_irc *irc;
struct dect_transceiver_event event[];
};
static inline void *dect_transceiver_priv(const struct dect_transceiver *trx)
{
return (void *)&trx->event[DECT_HALF_FRAME_SIZE / trx->ops->eventrate];
}
static inline bool dect_slot_available(const struct dect_transceiver *trx, u8 slot)
{
return trx->ops->slotmask & (1 << slot);
}
extern struct dect_transceiver *dect_transceiver_alloc(const struct dect_transceiver_ops *ops,
unsigned int priv);
extern void dect_transceiver_free(struct dect_transceiver *trx);
extern int dect_register_transceiver(struct dect_transceiver *trx);
extern void dect_unregister_transceiver(struct dect_transceiver *trx);
extern void dect_transceiver_enable(struct dect_transceiver *trx);
extern void dect_transceiver_disable(struct dect_transceiver *trx);
extern void dect_transceiver_confirm(struct dect_transceiver *trx);
extern void dect_transceiver_unlock(struct dect_transceiver *trx);
extern void dect_transceiver_lock(struct dect_transceiver *trx, u8 slot);
extern int dect_transceiver_set_band(struct dect_transceiver *trx, u8 bandnum);
static inline void dect_set_channel_mode(struct dect_transceiver *trx,
const struct dect_channel_desc *chd,
enum dect_slot_states mode)
{
trx->ops->set_mode(trx, chd, mode);
trx->slots[chd->slot].state = mode;
trx->slots[chd->slot].chd.pkt = chd->pkt;
trx->slots[chd->slot].chd.b_fmt = chd->b_fmt;
}
static inline void dect_set_carrier(struct dect_transceiver *trx,
u8 slot, u8 carrier)
{
trx->slots[slot].chd.carrier = carrier;
trx->slots[slot].rssi = 0;
trx->ops->set_carrier(trx, slot, carrier);
}
static inline void dect_transceiver_tx(struct dect_transceiver *trx,
struct sk_buff *skb)
{
u8 slot = DECT_TRX_CB(skb)->slot;
trx->ops->tx(trx, skb);
trx->slots[slot].tx_bytes += skb->len;
trx->slots[slot].tx_packets++;
}
extern struct sk_buff *dect_transceiver_alloc_skb(struct dect_transceiver *trx, u8 slot);
static inline struct dect_transceiver_event *
dect_transceiver_event(struct dect_transceiver *trx, u8 n, u8 slotpos)
{
struct dect_transceiver_event *event;
event = &trx->event[n];
if (unlikely(!atomic_add_unless(&event->busy, 1, 1))) {
trx->stats.event_busy++;
return NULL;
}
event->slotpos = slotpos;
return event;
}
static inline void dect_transceiver_record_rssi(struct dect_transceiver_event *event,
u8 slot, u8 rssi)
{
u8 idx;
idx = slot % event->trx->ops->eventrate;
event->rssi[idx] = rssi;
event->rssi_mask |= 1 << idx;
}
static inline void dect_release_transceiver_event(struct dect_transceiver_event *event)
{
event->rssi_mask = 0;
smp_mb__before_atomic_dec();
atomic_dec(&event->busy);
}
extern struct list_head dect_transceiver_list;
enum dect_transceiver_events {
DECT_TRANSCEIVER_REGISTER,
DECT_TRANSCEIVER_UNREGISTER,
};
extern void dect_register_notifier(struct notifier_block *nb);
extern void dect_unregister_notifier(struct notifier_block *nb);
#define DECT_TRX_GROUP_MAX 16
/**
* struct dect_transceiver_group
*
* @trx: Transceiver array
* @trxmask: Mask of present transceivers
* @latency: Maximum latency of all transceivers
* @blind_full_slots: combined blind full slots state of all transceivers
* @tasklet: Event processing tasklet
* @lock: Event list lock
* @events: List of queued events
* @seqno: Transceiver event loss detection
* @slot_low: First unhandled slot
* @slot_high: First slot after slot window
* @slots: merged events for window slot_low - slot_high
*/
struct dect_transceiver_group {
struct dect_transceiver *trx[DECT_TRX_GROUP_MAX];
u16 trxmask;
u8 latency;
u32 blind_full_slots;
struct tasklet_struct tasklet;
spinlock_t lock;
struct list_head events;
u32 seqno;
u8 slot_low;
u8 slot_high;
struct {
struct sk_buff_head queue;
u16 mask;
u8 rssi[DECT_TRX_GROUP_MAX];
} slots[DECT_HALF_FRAME_SIZE];
};
extern void dect_transceiver_group_init(struct dect_transceiver_group *trg);
extern int dect_transceiver_group_add(struct dect_transceiver_group *trg,
struct dect_transceiver *trx);
extern void dect_transceiver_group_remove(struct dect_transceiver_group *trg,
struct dect_transceiver *trx);
extern bool dect_transceiver_channel_available(const struct dect_transceiver *trx,
const struct dect_channel_desc *chd);
extern bool dect_transceiver_reserve(struct dect_transceiver_group *trg,
struct dect_transceiver *trx,
const struct dect_channel_desc *chd);
extern bool dect_transceiver_release(struct dect_transceiver_group *trg,
struct dect_transceiver *trx,
const struct dect_channel_desc *chd);
extern void dect_transceiver_queue_event(struct dect_transceiver *trx,
struct dect_transceiver_event *ev);
#define dect_first_transceiver(trg) \
({ \
struct dect_transceiver_group *_trg = (void *)(trg); \
u32 mask = _trg->trxmask; \
mask ? (_trg)->trx[ffs(mask) - 1] : NULL; })
#define dect_next_transceiver(trx, trg) \
({ \
struct dect_transceiver_group *_trg = (void *)(trg); \
u32 mask = _trg->trxmask; \
mask &= ~((1 << ((trx)->index + 1)) - 1); \
mask ? (_trg)->trx[ffs(mask) - 1] : NULL; })
#define dect_foreach_transceiver(trx, trg) \
for ((trx) = dect_first_transceiver(trg); \
(trx) != NULL; \
(trx) = dect_next_transceiver(trx, trg))
#define dect_last_transceiver(trg) \
({ \
struct dect_transceiver_group *_trg = (void *)(trg); \
u32 mask = _trg->trxmask; \
mask ? (_trg)->trx[fls(mask) - 1] : NULL; })
#define dect_prev_transceiver(trx, trg) \
({ \
struct dect_transceiver_group *_trg = (void *)(trg); \
u32 mask = _trg->trxmask; \
mask &= (1 << (trx)->index) - 1; \
mask ? (_trg)->trx[fls(mask) - 1] : NULL; })
#define dect_foreach_transceiver_reverse(trx, trg) \
for ((trx) = dect_last_transceiver(trg); \
(trx) != NULL; \
(trx) = dect_prev_transceiver(trx, trg))
extern int dect_transceiver_module_init(void);
extern void dect_transceiver_module_exit(void);
#endif /* _NET_DECT_TRANSCEIVER_H */

View File

@ -239,6 +239,7 @@ source "net/ax25/Kconfig"
source "net/can/Kconfig"
source "net/irda/Kconfig"
source "net/bluetooth/Kconfig"
source "net/dect/Kconfig"
source "net/rxrpc/Kconfig"
config FIB_RULES

View File

@ -38,6 +38,7 @@ obj-$(CONFIG_AX25) += ax25/
obj-$(CONFIG_CAN) += can/
obj-$(CONFIG_IRDA) += irda/
obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_DECT) += dect/
obj-$(CONFIG_SUNRPC) += sunrpc/
obj-$(CONFIG_AF_RXRPC) += rxrpc/
obj-$(CONFIG_ATM) += atm/

View File

@ -155,7 +155,7 @@ static const char *af_family_key_strings[AF_MAX+1] = {
"sk_lock-27" , "sk_lock-28" , "sk_lock-AF_CAN" ,
"sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" ,
"sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" ,
"sk_lock-AF_MAX"
"sk-lock-AF_DECT" , "sk_lock-AF_MAX"
};
static const char *af_family_slock_key_strings[AF_MAX+1] = {
"slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" ,
@ -170,7 +170,7 @@ static const char *af_family_slock_key_strings[AF_MAX+1] = {
"slock-27" , "slock-28" , "slock-AF_CAN" ,
"slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" ,
"slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" ,
"slock-AF_MAX"
"slock-AF_DECT" , "slock-AF_MAX"
};
static const char *af_family_clock_key_strings[AF_MAX+1] = {
"clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" ,
@ -185,7 +185,7 @@ static const char *af_family_clock_key_strings[AF_MAX+1] = {
"clock-27" , "clock-28" , "clock-AF_CAN" ,
"clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" ,
"clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" ,
"clock-AF_MAX"
"clock-AF_DECT" , "clock-AF_MAX"
};
/*

59
net/dect/Kconfig Normal file
View File

@ -0,0 +1,59 @@
menuconfig DECT
tristate "DECT protocol support"
help
This option enables support for the DECT protocol.
If unsure, say N.
if DECT
config DECT_CSF
tristate "DECT Cell Site Functions (CSF) support"
help
This option enables support for DECT Cell Site Functions. A DECT
cell is a radio endpoint containing one or more transceivers.
If unsure, say N.
config DECT_RAW
tristate "DECT raw sockets"
depends on DECT_CSF
help
This option enables support for PF_DECT raw sockets. DECT raw
sockets are used to receive raw frames from DECT devices.
If unsure, say N.
config DECT_CCF
tristate "DECT Cluster Control Functions (CCF) support"
help
This option enables support for the DECT Cluster Control Functions.
A DECT cluster is a Portable radio Termination (PT), containing a
single cell, or a Fixed radio Termination (FT), containing up to
8 cells.
If unsure, say N.
config DECT_LU1_SAP
tristate "DECT DLC LU1 SAP sockets"
select DECT_CCF
help
This option enables support for PF_DECT DLC LU1 SAP sockets. DECT
DLC LU1 SAP sockets are used for the TRUP (TRansparent UnProtected)
service, most commonly used for audio.
If unsure, say N.
config DECT_CCP
tristate "DECT Cell Control Protocol support"
depends on DECT_CSF || DECT_CCF
select TIPC
help
This option enables support for the DECT Cell Control Protocol.
This can be used to remotely control one or multiple DECT cells
by the DECT cluster control functions.
If unsure, say N.
endif

17
net/dect/Makefile Normal file
View File

@ -0,0 +1,17 @@
dect-y += core.o identities.o dect_netlink.o af_dect.o
dect_csf-y += mac_csf.o transceiver.o
dect_ccf-y += mac_ccf.o
dect_ccf-y += dlc.o
dect_ccf-y += dlc_cplane.o dlc_b_sap.o dlc_s_sap.o
dect_ccf-y += dlc_uplane.o dlc_lu1_sap.o
dect-y += $(dect_ccf-y) $(dect_csf-y) ccp.o
obj-$(CONFIG_DECT) += dect.o
#obj-$(CONFIG_DECT_CSF) += dect_csf.o
obj-$(CONFIG_DECT_RAW) += raw.o
#obj-$(CONFIG_DECT_CCF) += dect_ccf.o
obj-$(CONFIG_DECT_B_SAP) += dlc_b_sap.o
#obj-$(CONFIG_DECT_LU1_SAP) += dlc_lu1_sap.o

391
net/dect/af_dect.c Normal file
View File

@ -0,0 +1,391 @@
/*
* DECT sockets
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/poll.h>
#include <linux/dect.h>
#include <net/sock.h>
#include <net/dect/dect.h>
static struct dect_proto *dect_protos[DECT_PROTO_NUM];
static DEFINE_SPINLOCK(dect_proto_lock);
void (*dect_raw_rcv_hook)(struct sk_buff *skb);
EXPORT_SYMBOL_GPL(dect_raw_rcv_hook);
int dect_proto_register(struct dect_proto *proto)
{
int err;
err = proto_register(&proto->proto, true);
if (err < 0)
return err;
spin_lock(&dect_proto_lock);
dect_protos[proto->protocol] = proto;
spin_unlock(&dect_proto_lock);
return 0;
}
EXPORT_SYMBOL_GPL(dect_proto_register);
void dect_proto_unregister(struct dect_proto *proto)
{
spin_lock(&dect_proto_lock);
dect_protos[proto->protocol] = NULL;
spin_unlock(&dect_proto_lock);
proto_unregister(&proto->proto);
}
EXPORT_SYMBOL_GPL(dect_proto_unregister);
static void dect_destruct(struct sock *sk)
{
__skb_queue_purge(&sk->sk_receive_queue);
__skb_queue_purge(&sk->sk_write_queue);
}
static int dect_release(struct socket *sock)
{
struct sock *sk = sock->sk;
long timeout;
if (sk == NULL)
return 0;
timeout = 0;
if (sock_flag(sk, SOCK_LINGER) && !(current->flags & PF_EXITING))
timeout = sk->sk_lingertime;
sock->sk = NULL;
sk->sk_prot->close(sk, timeout);
return 0;
}
static int dect_bind(struct socket *sock, struct sockaddr *uaddr, int len)
{
struct sock *sk = sock->sk;
int err;
err = 0;
if (sk->sk_prot->bind != NULL)
err = sk->sk_prot->bind(sk, uaddr, len);
return err;
}
static int dect_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
int err;
lock_sock(sk);
err = -EINVAL;
if (sock->state != SS_UNCONNECTED ||
(sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET))
goto out;
if (sk->sk_state != DECT_SK_RELEASED && sk->sk_state != DECT_SK_LISTEN)
goto out;
if (sk->sk_state != DECT_SK_LISTEN)
sk->sk_prot->hash(sk);
sk->sk_max_ack_backlog = backlog;
err = 0;
out:
release_sock(sk);
return err;
}
static int dect_accept(struct socket *sock, struct socket *newsock, int flags)
{
struct sock *sk = sock->sk, *newsk;
int err;
newsk = sk->sk_prot->accept(sk, flags, &err);
if (newsk == NULL)
return err;
lock_sock(newsk);
sock_graft(newsk, newsock);
newsock->state = SS_CONNECTED;
release_sock(newsk);
return 0;
}
static unsigned int dect_poll(struct file *file, struct socket *sock,
struct poll_table_struct *wait)
{
struct sock *sk = sock->sk;
unsigned int mask;
poll_wait(file, sk->sk_sleep, wait);
mask = 0;
if (sk->sk_state == DECT_SK_LISTEN) {
if (!hlist_empty(&dect_csk(sk)->accept_queue))
return POLLIN | POLLRDNORM;
return 0;
}
/* exceptional events? */
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP;
if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP;
/* readable? */
if (!skb_queue_empty(&sk->sk_receive_queue) ||
(sk->sk_shutdown & RCV_SHUTDOWN))
mask |= POLLIN | POLLRDNORM;
/* Connection-based need to check for termination and startup */
if (sk->sk_state == DECT_SK_RELEASED)
mask |= POLLHUP;
/* connection hasn't started yet? */
if (sk->sk_state == DECT_SK_ESTABLISH_PENDING)
return mask;
/* writable? */
if (sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
return mask;
}
static int dect_connect(struct socket *sock, struct sockaddr *uaddr, int len,
int flags)
{
struct sock *sk = sock->sk;
long timeo;
int err;
lock_sock(sk);
switch (sock->state) {
case SS_CONNECTED:
err = -EISCONN;
goto out;
case SS_CONNECTING:
err = -EALREADY;
goto out;
case SS_UNCONNECTED:
err = -EISCONN;
if (sk->sk_state != DECT_SK_RELEASED)
goto out;
err = sk->sk_prot->connect(sk, uaddr, len);
if (err < 0)
goto out;
sock->state = SS_CONNECTING;
err = -EINPROGRESS;
break;
default:
err = -EINVAL;
goto out;
}
if (sk->sk_state == DECT_SK_ESTABLISH_PENDING) {
timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
err = sk_stream_wait_connect(sk, &timeo);
if (err < 0)
goto out;
err = sock_intr_errno(timeo);
if (signal_pending(current))
goto out;
}
if (sk->sk_state == DECT_SK_RELEASED)
goto sock_error;
sock->state = SS_CONNECTED;
err = 0;
out:
release_sock(sk);
return err;
sock_error:
// FIXME
goto out;
}
static int dect_getname(struct socket *sock, struct sockaddr *uaddr, int *len,
int peer)
{
const struct dect_proto *p;
/* AF_DECT uses different address formats for the different SAPs */
p = container_of(sock->sk->sk_prot, struct dect_proto, proto);
if (p->getname != NULL)
return p->getname(sock->sk, uaddr, len, peer);
*len = 0;
return 0;
}
static int dect_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size)
{
struct sock *sk = sock->sk;
return sk->sk_prot->sendmsg(iocb, sk, msg, size);
}
static int dect_create(struct net *net, struct socket *sock, int protocol)
{
struct dect_proto *p;
struct sock *sk;
int err = 0;
if (protocol < 0 || protocol >= DECT_PROTO_NUM)
return -EPROTONOSUPPORT;
#ifdef CONFIG_MODULES
if (dect_protos[protocol] == NULL) {
err = request_module("net-pf-%d-proto-%d", PF_DECT, protocol);
if (err < 0)
return err;
}
#endif
spin_lock(&dect_proto_lock);
p = dect_protos[protocol];
if (p != NULL && !try_module_get(p->proto.owner))
p = NULL;
spin_unlock(&dect_proto_lock);
if (p == NULL)
return -EPROTONOSUPPORT;
if (p->type != sock->type) {
err = -EPROTONOSUPPORT;
goto err;
}
if (cap_valid(p->capability) && !capable(p->capability)) {
err = -EACCES;
goto err;
}
sock->state = SS_UNCONNECTED;
sock->ops = p->ops;
sk = sk_alloc(net, PF_DECT, GFP_KERNEL, &p->proto);
if (sk == NULL) {
err = -ENOMEM;
goto err;
}
sock_init_data(sock, sk);
sk->sk_protocol = protocol;
sk->sk_destruct = dect_destruct;
if (sk->sk_prot->init != NULL) {
err = sk->sk_prot->init(sk);
if (err < 0) {
sock_orphan(sk);
sock_put(sk);
}
}
err:
module_put(p->proto.owner);
return err;
}
const struct proto_ops dect_stream_ops = {
.family = PF_DECT,
.owner = THIS_MODULE,
.release = dect_release,
.bind = dect_bind,
.connect = dect_connect,
.socketpair = sock_no_socketpair,
.getname = dect_getname,
.poll = dect_poll,
.ioctl = sock_no_ioctl,
.listen = dect_listen,
.accept = dect_accept,
.shutdown = sock_no_shutdown,
.setsockopt = sock_no_setsockopt,
.getsockopt = sock_no_getsockopt,
.sendmsg = dect_sendmsg,
.recvmsg = sock_common_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
};
const struct proto_ops dect_dgram_ops = {
.family = PF_DECT,
.owner = THIS_MODULE,
.release = dect_release,
.bind = dect_bind,
.connect = sock_no_connect,
.socketpair = sock_no_socketpair,
.getname = dect_getname,
.poll = datagram_poll,
.ioctl = sock_no_ioctl,
.listen = sock_no_listen,
.accept = sock_no_accept,
.shutdown = sock_no_shutdown,
.setsockopt = sock_no_setsockopt,
.getsockopt = sock_no_getsockopt,
.sendmsg = dect_sendmsg,
.recvmsg = sock_common_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
};
static struct net_proto_family dect_family_ops = {
.family = PF_DECT,
.create = dect_create,
.owner = THIS_MODULE,
};
int __init dect_af_module_init(void)
{
int err;
err = sock_register(&dect_family_ops);
if (err < 0)
goto err1;
err = dect_bsap_module_init();
if (err < 0)
goto err2;
err = dect_ssap_module_init();
if (err < 0)
goto err3;
err = dect_lu1_sap_module_init();
if (err < 0)
goto err4;
return 0;
err4:
dect_ssap_module_exit();
err3:
dect_bsap_module_exit();
err2:
sock_unregister(PF_DECT);
err1:
return err;
}
void dect_af_module_exit(void)
{
dect_lu1_sap_module_exit();
dect_bsap_module_exit();
dect_ssap_module_exit();
sock_unregister(PF_DECT);
}
MODULE_ALIAS_NETPROTO(PF_DECT);

682
net/dect/ccp.c Normal file
View File

@ -0,0 +1,682 @@
/*
* DECT Cell Control Protocol
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define DEBUG
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/net.h>
#include <linux/dect.h>
#include <net/dect/dect.h>
#include <net/dect/mac_csf.h>
#include <net/dect/mac_ccf.h>
#include <net/dect/ccp.h>
#include <net/tipc/tipc.h>
static struct sk_buff *dect_ccp_msg_alloc(size_t size)
{
struct sk_buff *skb;
size += sizeof(struct dect_ccp_msg_hdr) + 2 * LL_MAX_HEADER;
skb = alloc_skb(size, GFP_ATOMIC);
if (skb == NULL)
return NULL;
skb_reserve(skb, size);
return skb;
}
static void dect_ccp_build_msg(struct sk_buff *skb,
enum dect_ccp_primitives prim)
{
struct dect_ccp_msg_hdr *h;
h = (struct dect_ccp_msg_hdr *)skb_push(skb, sizeof(*h));
h->primitive = prim;
}
static int dect_ccp_send_to_cell(const struct dect_cell_handle *ch,
struct sk_buff *skb,
enum dect_ccp_primitives prim)
{
int err;
dect_ccp_build_msg(skb, prim);
err = tipc_send_buf(ch->portref, skb, skb->len);
if (err < 0 && net_ratelimit())
printk("Failed to send DECT CCP message\n");
return err;
}
static int dect_ccp_send_to_cluster(const struct dect_cluster_handle *clh,
struct sk_buff *skb,
enum dect_ccp_primitives prim)
{
int err;
dect_ccp_build_msg(skb, prim);
err = tipc_send_buf(clh->portref, skb, skb->len);
if (err < 0 && net_ratelimit())
printk("Failed to send DECT CCP message\n");
return err;
}
static void dect_ccp_build_mbc_msg(struct sk_buff *skb, const struct dect_mbc_id *id)
{
struct dect_ccp_mbc_msg *msg;
msg = (struct dect_ccp_mbc_msg *)__skb_push(skb, sizeof(*msg));
msg->mcei = cpu_to_be32(id->mcei);
msg->pmid = cpu_to_be32(dect_build_pmid(&id->pmid));
msg->ari = cpu_to_be64(dect_build_ari(&id->ari));
msg->ecn = id->ecn;
}
static bool dect_ccp_parse_mbc_msg(struct dect_mbc_id *id, struct sk_buff *skb)
{
struct dect_ccp_mbc_msg *msg;
if (!pskb_may_pull(skb, sizeof(*msg)))
return false;
msg = (struct dect_ccp_mbc_msg *)skb->data;
__skb_pull(skb, sizeof(*msg));
id->mcei = be32_to_cpu(msg->mcei);
dect_parse_pmid(&id->pmid, be32_to_cpu(msg->pmid));
if (!dect_parse_ari(&id->ari, be64_to_cpu(msg->ari)))
return false;
id->ecn = msg->ecn;
return true;
}
static void dect_ccp_build_sysinfo(struct sk_buff *skb,
const struct dect_ari *pari, u8 rpn,
const struct dect_si *si)
{
struct dect_ccp_sysinfo_msg *msg;
unsigned int i;
msg = (struct dect_ccp_sysinfo_msg *)__skb_push(skb, sizeof(*msg));
msg->pari = cpu_to_be64(dect_build_ari(pari));
for (i = 0; i < si->num_saris; i++)
msg->sari[i] = cpu_to_be64(dect_build_ari(&si->sari[i].ari));
msg->num_saris = i;
msg->fpc = cpu_to_be64(si->fpc.fpc);
msg->hlc = cpu_to_be64(si->fpc.hlc);
msg->mfn = cpu_to_be32(si->mfn.num);
msg->rpn = rpn;
}
static bool dect_ccp_parse_sysinfo(struct dect_ari *pari, u8 *rpn,
struct dect_si *si, struct sk_buff *skb)
{
struct dect_ccp_sysinfo_msg *msg;
unsigned int i;
if (!pskb_may_pull(skb, sizeof(*msg)))
return false;
msg = (struct dect_ccp_sysinfo_msg *)skb->data;
__skb_pull(skb, sizeof(*msg));
if (!dect_parse_ari(pari, be64_to_cpu(msg->pari)))
return false;
*rpn = msg->rpn;
if (msg->num_saris > ARRAY_SIZE(si->sari))
return false;
for (i = 0; i < msg->num_saris; i++) {
if (!dect_parse_ari(&si->sari[i].ari,
be64_to_cpu(msg->sari[i])))
return false;
}
si->fpc.fpc = be64_to_cpu(msg->fpc);
si->fpc.hlc = be64_to_cpu(msg->hlc);
si->mfn.num = be32_to_cpu(msg->mfn);
return true;
}
static int dect_ccp_send_set_mode(const struct dect_cell_handle *ch,
enum dect_cluster_modes mode)
{
struct dect_ccp_mode_msg *msg;
struct sk_buff *skb;
skb = dect_ccp_msg_alloc(sizeof(*msg));
if (skb == NULL)
return -ENOMEM;
msg = (struct dect_ccp_mode_msg *)__skb_push(skb, sizeof(*msg));
msg->mode = mode;
return dect_ccp_send_to_cell(ch, skb, DECT_CCP_SET_MODE);
}
static void dect_ccp_parse_set_mode(const struct dect_cell_handle *ch,
struct sk_buff *skb)
{
struct dect_ccp_mode_msg *msg;
if (!pskb_may_pull(skb, sizeof(*msg)))
return;
msg = (struct dect_ccp_mode_msg *)skb->data;
ch->ops->set_mode(ch, msg->mode);
}
static int dect_ccp_send_scan(const struct dect_cell_handle *ch,
const struct dect_llme_req *lreq,
const struct dect_ari *ari,
const struct dect_ari *ari_mask)
{
struct dect_ccp_scan_msg *msg;
struct sk_buff *skb;
skb = dect_ccp_msg_alloc(sizeof(*msg));
if (skb == NULL)
return -ENOMEM;
msg = (struct dect_ccp_scan_msg *)__skb_push(skb, sizeof(*msg));
msg->ari = cpu_to_be64(dect_build_ari(ari));
msg->ari_mask = cpu_to_be64(dect_build_ari(ari_mask));
return dect_ccp_send_to_cell(ch, skb, DECT_CCP_SCAN);
}
static void dect_ccp_parse_scan(const struct dect_cell_handle *ch,
struct sk_buff *skb)
{
struct dect_ccp_scan_msg *msg;
struct dect_ari ari, ari_mask;
if (!pskb_may_pull(skb, sizeof(*msg)))
return;
msg = (struct dect_ccp_scan_msg *)skb->data;
if (!dect_parse_ari(&ari, be64_to_cpu(msg->ari)))
return;
if (!dect_parse_ari(&ari_mask, be64_to_cpu(msg->ari_mask)))
return;
ch->ops->scan(ch, NULL, &ari, &ari_mask);
}
static int dect_ccp_send_preload(const struct dect_cell_handle *ch,
const struct dect_ari *pari, u8 rpn,
const struct dect_si *si)
{
struct sk_buff *skb;
skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_sysinfo_msg));
if (skb == NULL)
return -ENOMEM;
dect_ccp_build_sysinfo(skb, pari, rpn, si);
return dect_ccp_send_to_cell(ch, skb, DECT_CCP_PRELOAD);
}
static void dect_ccp_parse_preload(const struct dect_cell_handle *ch,
struct sk_buff *skb)
{
struct dect_ari pari;
struct dect_si si;
u8 rpn;
if (!dect_ccp_parse_sysinfo(&pari, &rpn, &si, skb))
return;
ch->ops->preload(ch, &pari, rpn, &si);
}
static int dect_ccp_send_enable(const struct dect_cell_handle *ch)
{
struct sk_buff *skb;
skb = dect_ccp_msg_alloc(0);
if (skb == NULL)
return -ENOMEM;
return dect_ccp_send_to_cell(ch, skb, DECT_CCP_ENABLE);
}
static void dect_ccp_parse_enable(const struct dect_cell_handle *ch,
struct sk_buff *skb)
{
ch->ops->enable(ch);
}
static int dect_ccp_send_tbc_initiate(const struct dect_cell_handle *ch,
const struct dect_mbc_id *id,
const struct dect_channel_desc *cd)
{
struct sk_buff *skb;
skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_mbc_msg));
if (skb == NULL)
return -ENOMEM;
dect_ccp_build_mbc_msg(skb, id);
return dect_ccp_send_to_cell(ch, skb, DECT_CCP_TBC_INITIATE);
}
static void dect_ccp_parse_tbc_initiate(const struct dect_cell_handle *ch,
struct sk_buff *skb)
{
struct dect_mbc_id id;
if (!dect_ccp_parse_mbc_msg(&id, skb))
return;
ch->ops->tbc_initiate(ch, &id, NULL);
}
static void dect_ccp_parse_tbc_confirm(const struct dect_cell_handle *ch,
struct sk_buff *skb)
{
struct dect_mbc_id id;
if (!dect_ccp_parse_mbc_msg(&id, skb))
return;
ch->ops->tbc_confirm(ch, &id);
}
static void dect_ccp_parse_tbc_release(const struct dect_cell_handle *ch,
struct sk_buff *skb)
{
struct dect_mbc_id id;
if (!dect_ccp_parse_mbc_msg(&id, skb))
return;
ch->ops->tbc_release(ch, &id);
}
static int dect_ccp_send_tbc_confirm(const struct dect_cell_handle *ch,
const struct dect_mbc_id *id)
{
struct sk_buff *skb;
skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_mbc_msg));
if (skb == NULL)
return -ENOMEM;
dect_ccp_build_mbc_msg(skb, id);
return dect_ccp_send_to_cell(ch, skb, DECT_CCP_TBC_CONFIRM);
}
static void dect_ccp_send_tbc_release(const struct dect_cell_handle *ch,
const struct dect_mbc_id *id)
{
struct sk_buff *skb;
skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_mbc_msg));
if (skb == NULL)
return;
dect_ccp_build_mbc_msg(skb, id);
dect_ccp_send_to_cell(ch, skb, DECT_CCP_TBC_RELEASE);
}
static int dect_ccp_send_mbc_conn_indicate(const struct dect_cluster_handle *clh,
const struct dect_cell_handle *ch,
const struct dect_mbc_id *id)
{
struct sk_buff *skb;
skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_mbc_msg));
if (skb == NULL)
return -ENOMEM;
dect_ccp_build_mbc_msg(skb, id);
return dect_ccp_send_to_cluster(clh, skb, DECT_CCP_MBC_CONN_INDICATE);
}
static void dect_ccp_parse_mbc_conn_indicate(const struct dect_cell_handle *ch,
struct sk_buff *skb)
{
const struct dect_cluster_handle *clh = ch->clh;
struct dect_mbc_id id;
if (!dect_ccp_parse_mbc_msg(&id, skb))
return;
clh->ops->mbc_conn_indicate(clh, ch, &id);
}
static int dect_ccp_send_mbc_conn_notify(const struct dect_cluster_handle *clh,
const struct dect_mbc_id *id,
enum dect_tbc_state state)
{
struct sk_buff *skb;
skb = dect_ccp_msg_alloc(sizeof(struct dect_ccp_mbc_msg));
if (skb == NULL)
return -ENOMEM;
dect_ccp_build_mbc_msg(skb, id);
return dect_ccp_send_to_cluster(clh, skb, DECT_CCP_MBC_CONN_NOTIFY);
}
static void dect_ccp_parse_mbc_conn_notify(const struct dect_cell_handle *ch,
struct sk_buff *skb)
{
const struct dect_cluster_handle *clh = ch->clh;
struct dect_mbc_id id;
enum dect_tbc_state state = 0;
if (!dect_ccp_parse_mbc_msg(&id, skb))
return;
clh->ops->mbc_conn_notify(clh, &id, state);
}
static void dect_ccp_send_mbc_data_indicate(const struct dect_cluster_handle *clh,
const struct dect_mbc_id *id,
enum dect_data_channels chan,
struct sk_buff *skb)
{
dect_ccp_build_mbc_msg(skb, id);
dect_ccp_send_to_cluster(clh, skb, DECT_CCP_MBC_DATA_INDICATE);
}
static void dect_ccp_parse_mbc_data_indicate(const struct dect_cell_handle *ch,
struct sk_buff *skb)
{
const struct dect_cluster_handle *clh = ch->clh;
struct dect_mbc_id id;
if (!dect_ccp_parse_mbc_msg(&id, skb))
return;
clh->ops->mbc_data_indicate(clh, &id, 0, skb); // FIXME
}
static void dect_ccp_rcv_cell_msg(void *handle, u32 portref,
struct sk_buff **pskb,
const u8 *data, u32 size)
{
struct dect_cell_handle *ch = handle;
struct dect_ccp_msg_hdr *h;
struct sk_buff *skb = *pskb;
if (!pskb_may_pull(skb, sizeof(*h)))
return;
h = (struct dect_ccp_msg_hdr *)skb->data;
__skb_pull(skb, sizeof(*h));
switch (h->primitive) {
case DECT_CCP_MBC_CONN_INDICATE:
return dect_ccp_parse_mbc_conn_indicate(ch, skb);
case DECT_CCP_MBC_CONN_NOTIFY:
return dect_ccp_parse_mbc_conn_notify(ch, skb);
case DECT_CCP_MBC_DATA_INDICATE:
return dect_ccp_parse_mbc_data_indicate(ch, skb);
}
}
static void dect_ccp_cl_disconnect(void *handle, u32 portref,
struct sk_buff **pskb,
const u8 *data, u32 size, int reason)
{
struct dect_cell_handle *ch = handle;
struct dect_cluster_handle *clh = ch->clh;
printk("cell disconnected\n");
clh->ops->unbind(clh, ch);
kfree(ch);
}
static const struct dect_csf_ops dect_ccp_csf_ops = {
.set_mode = dect_ccp_send_set_mode,
.scan = dect_ccp_send_scan,
.preload = dect_ccp_send_preload,
.enable = dect_ccp_send_enable,
.tbc_initiate = dect_ccp_send_tbc_initiate,
.tbc_confirm = dect_ccp_send_tbc_confirm,
.tbc_release = dect_ccp_send_tbc_release,
};
static void dect_ccp_cl_named_msg(void *handle, u32 portref,
struct sk_buff **pskb,
const u8 *data, u32 size,
u32 importance,
const struct tipc_portid *source,
const struct tipc_name_seq *dest)
{
struct dect_cluster *cl = handle;
struct dect_cluster_handle *clh = &cl->handle;
struct dect_cell_handle *ch;
struct iovec ack = { NULL, 0};
int err;
ch = kzalloc(sizeof(*ch), GFP_ATOMIC);
if (ch == NULL)
goto err1;
ch->ops = &dect_ccp_csf_ops;
err = tipc_createport(cl->tipc_id, ch, TIPC_HIGH_IMPORTANCE,
NULL, NULL, dect_ccp_cl_disconnect,
NULL, NULL, dect_ccp_rcv_cell_msg, NULL,
&ch->portref);
if (err < 0)
goto err2;
err = tipc_connect2port(ch->portref, source);
if (err < 0)
goto err3;
err = tipc_send(ch->portref, 1, &ack);
if (err < 0)
goto err3;
err = clh->ops->bind(clh, ch);
if (err < 0)
goto err4;
return;
err4:
tipc_disconnect(ch->portref);
err3:
tipc_deleteport(ch->portref);
err2:
kfree(ch);
err1:
return;
}
/**
* dect_ccp_cluster_init - Initialize a cluster control CCP instance
*
* @cl: DECT cluster
*/
int dect_ccp_cluster_init(struct dect_cluster *cl)
{
struct tipc_name_seq seq;
int err;
err = tipc_attach(&cl->tipc_id, NULL, NULL);
if (err < 0)
goto err1;
err = tipc_createport(cl->tipc_id, cl, TIPC_HIGH_IMPORTANCE,
NULL, NULL, NULL, NULL, dect_ccp_cl_named_msg,
NULL, NULL, &cl->tipc_portref);
if (err < 0)
goto err2;
seq.type = DECT_CCP_TIPC_TYPE;
seq.lower = DECT_CCP_CLUSTER_PORT_BASE + cl->index;
seq.upper = DECT_CCP_CLUSTER_PORT_BASE + cl->index;
err = tipc_publish(cl->tipc_portref, TIPC_CLUSTER_SCOPE, &seq);
if (err < 0)
goto err3;
return 0;
err3:
tipc_deleteport(cl->tipc_portref);
err2:
tipc_detach(cl->tipc_id);
err1:
return err;
}
void dect_ccp_cluster_shutdown(struct dect_cluster *cl)
{
tipc_detach(cl->tipc_id);
}
static void dect_ccp_rcv_cluster_msg(void *handle, u32 portref,
struct sk_buff **pskb,
const u8 *data, u32 size)
{
struct sk_buff *skb = *pskb;
struct dect_cell_handle *ch = handle;
struct dect_ccp_msg_hdr *h;
if (!pskb_may_pull(skb, sizeof(*h)))
return;
h = (struct dect_ccp_msg_hdr *)skb->data;
__skb_pull(skb, sizeof(*h));
switch (h->primitive) {
case DECT_CCP_SET_MODE:
return dect_ccp_parse_set_mode(ch, skb);
case DECT_CCP_SCAN:
return dect_ccp_parse_scan(ch, skb);
case DECT_CCP_ENABLE:
return dect_ccp_parse_enable(ch, skb);
case DECT_CCP_PRELOAD:
return dect_ccp_parse_preload(ch, skb);
case DECT_CCP_TBC_INITIATE:
return dect_ccp_parse_tbc_initiate(ch, skb);
case DECT_CCP_TBC_CONFIRM:
return dect_ccp_parse_tbc_confirm(ch, skb);
case DECT_CCP_TBC_RELEASE:
return dect_ccp_parse_tbc_release(ch, skb);
}
}
static void dect_ccp_cluster_disconnect(void *handle, u32 portref,
struct sk_buff **pskb,
const u8 *data, u32 size, int reason)
{
printk("Cluster disconnected\n");
#if 0
struct dect_cell_handle *clh = handle;
clh->ops->unbind(clh);
#endif
}
static void dect_ccp_subscr_rcv(void *handle, u32 portref,
struct sk_buff **pskb,
const u8 *data, u32 size)
{
struct dect_cell_handle *ch = handle;
struct dect_cluster_handle *clh = ch->clh;
struct sk_buff *skb = *pskb;
struct tipc_event *ev;
struct tipc_name name;
int err;
if (!pskb_may_pull(skb, sizeof(*ev)))
return;
ev = (struct tipc_event *)skb->data;
if (ev->event != TIPC_PUBLISHED)
return;
/* Connect to cluster */
err = tipc_createport(clh->tipc_id, ch, TIPC_HIGH_IMPORTANCE,
NULL, NULL, dect_ccp_cluster_disconnect,
NULL, NULL, dect_ccp_rcv_cluster_msg, NULL,
&clh->portref);
if (err < 0)
goto err1;
name.type = DECT_CCP_TIPC_TYPE;
name.instance = DECT_CCP_CLUSTER_PORT_BASE + clh->index;
err = tipc_send2name(clh->portref, &name, 0, 0, NULL);
if (err < 0)
goto err2;
return;
err2:
tipc_deleteport(clh->portref);
err1:
return;
}
/**
* dect_ccp_cell_init - Initialize a cell CCP instance
*
* @cell: DECT cell
*/
static int dect_ccp_bind_cell(struct dect_cluster_handle *clh,
struct dect_cell_handle *ch)
{
struct tipc_subscr subscr;
struct iovec iov = { &subscr, sizeof(subscr) };
struct tipc_name tname;
int err;
err = tipc_attach(&clh->tipc_id, NULL, NULL);
if (err < 0)
goto err1;
ch->clh = clh;
/* Connect to topology service and subscribe to cluster port */
err = tipc_createport(clh->tipc_id, ch, TIPC_CRITICAL_IMPORTANCE,
NULL, NULL, NULL, NULL, NULL,
dect_ccp_subscr_rcv, NULL, &clh->tportref);
if (err < 0)
goto err2;
subscr.seq.type = DECT_CCP_TIPC_TYPE;
subscr.seq.lower = DECT_CCP_CLUSTER_PORT_BASE + clh->index;
subscr.seq.upper = DECT_CCP_CLUSTER_PORT_BASE + clh->index;
subscr.timeout = TIPC_WAIT_FOREVER;
subscr.filter = TIPC_SUB_PORTS;
memset(&subscr.usr_handle, 0, sizeof(subscr.usr_handle));
tname.type = TIPC_TOP_SRV;
tname.instance = TIPC_TOP_SRV;
err = tipc_send2name(clh->tportref, &tname, 0, 1, &iov);
if (err < 0)
goto err3;
return 0;
err3:
tipc_deleteport(clh->tportref);
err2:
tipc_detach(clh->tipc_id);
err1:
return err;
}
static void dect_ccp_unbind_cell(struct dect_cluster_handle *clh,
struct dect_cell_handle *ch)
{
tipc_detach(clh->tipc_id);
}
static void dect_ccp_send_bmc_page_indicate(const struct dect_cluster_handle *clh,
struct sk_buff *skb)
{
}
static const struct dect_ccf_ops dect_ccp_ccf_ops = {
.bind = dect_ccp_bind_cell,
.unbind = dect_ccp_unbind_cell,
.mbc_conn_indicate = dect_ccp_send_mbc_conn_indicate,
.mbc_conn_notify = dect_ccp_send_mbc_conn_notify,
.mbc_data_indicate = dect_ccp_send_mbc_data_indicate,
.bmc_page_indicate = dect_ccp_send_bmc_page_indicate,
};
struct dect_cluster_handle *dect_ccp_cell_init(struct dect_cell *cell, u8 clindex)
{
struct dect_cluster_handle *clh;
clh = kzalloc(sizeof(*clh), GFP_KERNEL);
if (clh == NULL)
return NULL;
clh->index = clindex;
clh->ops = &dect_ccp_ccf_ops;
return clh;
}

83
net/dect/core.c Normal file
View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/notifier.h>
#include <net/dect/dect.h>
#include <net/dect/transceiver.h>
static DEFINE_MUTEX(dect_cfg_mutex);
void dect_lock(void)
{
mutex_lock(&dect_cfg_mutex);
}
void dect_unlock(void)
{
mutex_unlock(&dect_cfg_mutex);
}
struct sk_buff *skb_append_frag(struct sk_buff *head, struct sk_buff *skb)
{
struct sk_buff **pprev;
if (head == NULL)
return skb;
pprev = &skb_shinfo(head)->frag_list;
while (*pprev != NULL)
pprev = &(*pprev)->next;
*pprev = skb;
head->data_len += skb->len;
head->len += skb->len;
head->truesize += skb->truesize;
return head;
}
static int __init dect_module_init(void)
{
int err;
err = dect_transceiver_module_init();
if (err < 0)
goto err1;
err = dect_netlink_module_init();
if (err < 0)
goto err2;
err = dect_af_module_init();
if (err < 0)
goto err3;
return 0;
err3:
dect_netlink_module_exit();
err2:
dect_af_module_exit();
err1:
return err;
}
static void __exit dect_module_exit(void)
{
dect_af_module_exit();
dect_netlink_module_exit();
dect_transceiver_module_exit();
}
module_init(dect_module_init);
module_exit(dect_module_exit);
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_DESCRIPTION("DECT protocol stack");
MODULE_LICENSE("GPL");

1268
net/dect/dect_netlink.c Normal file

File diff suppressed because it is too large Load Diff

191
net/dect/dlc.c Normal file
View File

@ -0,0 +1,191 @@
/*
* DECT DLC Layer
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define DEBUG
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/net.h>
#include <linux/dect.h>
#include <net/dect/dect.h>
static struct dect_mac_conn *
dect_mac_conn_get_by_mcei(const struct dect_cluster *cl, u32 mcei)
{
struct dect_mac_conn *mc;
list_for_each_entry(mc, &cl->mac_connections, list) {
if (mc->mcei == mcei)
return mc;
}
return NULL;
}
struct dect_mac_conn *
dect_mac_conn_get_by_mci(const struct dect_cluster *cl, const struct dect_mci *mci)
{
struct dect_mac_conn *mc;
list_for_each_entry(mc, &cl->mac_connections, list) {
if (!dect_ari_cmp(&mc->mci.ari, &mci->ari) &&
!dect_pmid_cmp(&mc->mci.pmid, &mci->pmid) &&
mc->mci.lcn == mci->lcn)
return mc;
}
return NULL;
}
struct dect_mac_conn *dect_mac_conn_init(struct dect_cluster *cl,
const struct dect_mci *mci,
const struct dect_mbc_id *id)
{
struct dect_mac_conn *mc;
mc = kzalloc(sizeof(*mc), GFP_ATOMIC);
if (mc == NULL)
return NULL;
mc->cl = cl;
mc->mcei = id != NULL ? id->mcei : dect_mbc_alloc_mcei(cl);
memcpy(&mc->mci, mci, sizeof(mc->mci));
mc->state = DECT_MAC_CONN_CLOSED;
list_add_tail(&mc->list, &cl->mac_connections);
return mc;
}
void dect_dlc_mac_conn_release(struct dect_mac_conn *mc)
{
list_del(&mc->list);
kfree(mc);
}
static void dect_mac_conn_state_change(struct dect_mac_conn *mc,
enum dect_mac_conn_states state)
{
mc->state = state;
dect_cplane_notify_state_change(mc);
}
int dect_dlc_mac_conn_establish(struct dect_mac_conn *mc)
{
struct dect_mbc_id mid = {
.mcei = mc->mcei,
.ari = mc->mci.ari,
.pmid = mc->mci.pmid,
.type = DECT_MAC_CONN_BASIC,
.ecn = mc->mci.lcn,
.service = mc->service,
};
int err;
err = dect_mbc_con_request(mc->cl, &mid);
if (err < 0)
return err;
dect_mac_conn_state_change(mc, DECT_MAC_CONN_OPEN_PENDING);
return 0;
}
int dect_dlc_mac_conn_confirm(struct dect_cluster *cl, u32 mcei,
enum dect_mac_service_types service)
{
struct dect_mac_conn *mc;
mc = dect_mac_conn_get_by_mcei(cl, mcei);
if (WARN_ON(mc == NULL))
return -ENOENT;
mc->service = service;
dect_mac_conn_state_change(mc, DECT_MAC_CONN_OPEN);
return 0;
}
int dect_dlc_mac_conn_indicate(struct dect_cluster *cl,
const struct dect_mbc_id *id)
{
struct dect_mac_conn *mc;
struct dect_mci mci = {
.ari = id->ari,
.pmid = id->pmid,
.lcn = id->ecn & DECT_LCN_MASK,
};
mc = dect_mac_conn_init(cl, &mci, id);
if (mc == NULL)
return -ENOMEM;
mc->service = id->service;
dect_mac_conn_state_change(mc, DECT_MAC_CONN_OPEN);
return 0;
}
int dect_dlc_mac_conn_disconnect(struct dect_cluster *cl, u32 mcei)
{
struct dect_mac_conn *mc;
mc = dect_mac_conn_get_by_mcei(cl, mcei);
if (WARN_ON(mc == NULL))
return -ENOENT;
dect_mac_conn_state_change(mc, DECT_MAC_CONN_CLOSED);
dect_dlc_mac_conn_release(mc);
return 0;
}
void dect_dlc_mac_co_data_indicate(struct dect_cluster *cl, u32 mcei,
enum dect_data_channels chan,
struct sk_buff *skb)
{
struct dect_mac_conn *mc;
mc = dect_mac_conn_get_by_mcei(cl, mcei);
if (WARN_ON(mc == NULL))
goto err;
pr_debug("dlc: data mcei %u mc %p chan %u len %u\n", mcei, mc, chan, skb->len);
switch (chan) {
case DECT_MC_C_S:
case DECT_MC_C_F:
return dect_cplane_rcv(mc, chan, skb);
case DECT_MC_I_N:
case DECT_MC_I_P:
return dect_uplane_rcv(mc, chan, skb);
default:
goto err;
}
err:
kfree_skb(skb);
}
struct sk_buff *dect_dlc_mac_co_dtr_indicate(struct dect_cluster *cl, u32 mcei,
enum dect_data_channels chan)
{
struct dect_mac_conn *mc;
mc = dect_mac_conn_get_by_mcei(cl, mcei);
if (mc == NULL) {
if (net_ratelimit())
printk("DLC: DTR no connection\n");
return NULL;
}
pr_debug("dlc: dtr mcei %u mc %p chan %u\n", mcei, mc, chan);
switch (chan) {
case DECT_MC_C_S:
case DECT_MC_C_F:
return dect_cplane_dtr(mc, chan);
case DECT_MC_I_N:
case DECT_MC_I_P:
return dect_uplane_dtr(mc, chan);
default:
return NULL;
}
}

223
net/dect/dlc_b_sap.c Normal file
View File

@ -0,0 +1,223 @@
/*
* DECT DLC B SAP sockets - DLC C-plane broadcast service access
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/net.h>
#include <linux/socket.h>
#include <linux/dect.h>
#include <net/sock.h>
#include <net/dect/dect.h>
static HLIST_HEAD(dect_bsap_sockets);
struct dect_bsap {
struct sock sk;
};
static inline struct dect_bsap *dect_bsap(struct sock *sk)
{
return (struct dect_bsap *)sk;
}
void dect_bsap_rcv(const struct dect_cluster *cl, struct sk_buff *skb)
{
struct hlist_node *node;
struct sk_buff *skb2;
struct sock *sk;
sk_for_each(sk, node, &dect_bsap_sockets) {
if (sk->sk_bound_dev_if &&
sk->sk_bound_dev_if != cl->index)
continue;
skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2 == NULL) {
sk->sk_err = -ENOMEM;
sk->sk_error_report(sk);
} else if (dect_sock_queue_rcv_skb(sk, skb2) < 0)
kfree_skb(skb2);
}
}
static void dect_bsap_close(struct sock *sk, long timeout)
{
sk_del_node_init(sk);
sock_put(sk);
}
static int dect_bsap_bind(struct sock *sk, struct sockaddr *uaddr, int len)
{
const struct sockaddr_dect *addr = (struct sockaddr_dect *)uaddr;
int err;
if (len < sizeof(*addr) || addr->dect_family != AF_DECT)
return -EINVAL;
if (addr->dect_index != 0 &&
!dect_cluster_get_by_index(addr->dect_index))
return -ENODEV;
lock_sock(sk);
err = -EINVAL;
if (!sk_unhashed(sk))
goto out;
sk->sk_bound_dev_if = addr->dect_index;
sk_add_node(sk, &dect_bsap_sockets);
err = 0;
out:
release_sock(sk);
return err;
}
static int dect_bsap_getname(struct sock *sk, struct sockaddr *uaddr, int *len,
int peer)
{
struct sockaddr_dect *addr = (struct sockaddr_dect *)uaddr;
if (peer)
return -EOPNOTSUPP;
addr->dect_family = AF_DECT;
addr->dect_index = sk->sk_bound_dev_if;
*len = sizeof(*addr);
return 0;
}
static int dect_bsap_recvmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, size_t len,
int noblock, int flags, int *addrlen)
{
struct sockaddr_dect *addr;
struct sk_buff *skb;
size_t copied = 0;
int err;
if (flags & MSG_OOB)
return -EOPNOTSUPP;
noblock = flags & MSG_DONTWAIT;
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (skb == NULL)
goto out;
//msg->msg_flags |= DECT_LB_CB(skb)->expedited ? MSG_OOB : 0;
copied = skb->len;
if (len < copied) {
msg->msg_flags |= MSG_TRUNC;
copied = len;
}
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (err < 0)
goto out_free;
if (msg->msg_name != NULL) {
addr = (struct sockaddr_dect *)msg->msg_name;
addr->dect_family = AF_DECT;
addr->dect_index = DECT_SK_CB(skb)->index;
msg->msg_namelen = sizeof(*addr);
}
sock_recv_timestamp(msg, sk, skb);
if (flags & MSG_TRUNC)
copied = skb->len;
out_free:
skb_free_datagram(sk, skb);
out:
return err ? : copied;
}
static int dect_bsap_sendmsg(struct kiocb *kiocb, struct sock *sk,
struct msghdr *msg, size_t len)
{
const struct sockaddr_dect *addr = msg->msg_name;
bool expedited = msg->msg_flags & MSG_OOB;
struct dect_cluster *cl;
struct sk_buff *skb;
int index;
int err;
if (msg->msg_namelen) {
if (addr->dect_family != AF_DECT)
return -EINVAL;
index = addr->dect_index;
} else
index = sk->sk_bound_dev_if;
/* Transmission is always in direction FP -> PP */
cl = dect_cluster_get_by_index(index);
if (cl == NULL)
return -ENODEV;
if (cl->mode != DECT_MODE_FP)
return -EOPNOTSUPP;
/* Valid frame sizes are 3 bytes (short frame), 5 bytes (long frame)
* or multiples of 5 bytes up to 30 bytes (extended frame). Extended
* frames can not use expedited operation. */
if (len != DECT_LB_SHORT_FRAME_SIZE &&
len != DECT_LB_LONG_FRAME_SIZE) {
if (len % DECT_LB_LONG_FRAME_SIZE != 0)
return -EINVAL;
if (len > DECT_LB_EXTENDED_FRAME_SIZE_MAX)
return -EMSGSIZE;
if (expedited)
return -EOPNOTSUPP;
}
skb = sock_alloc_send_skb(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);
if (skb == NULL)
goto err1;
err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
if (err < 0)
goto err2;
dect_bmc_mac_page_request(cl, skb, expedited);
return len;
err2:
kfree_skb(skb);
err1:
return err;
}
static struct dect_proto dect_bsap_proto __read_mostly = {
.type = SOCK_DGRAM,
.protocol = DECT_B_SAP,
.capability = CAP_NET_RAW,
.ops = &dect_dgram_ops,
.proto.name = "DECT_B_SAP",
.proto.owner = THIS_MODULE,
.proto.obj_size = sizeof(struct dect_bsap),
.proto.close = dect_bsap_close,
.proto.bind = dect_bsap_bind,
.proto.recvmsg = dect_bsap_recvmsg,
.proto.sendmsg = dect_bsap_sendmsg,
.getname = dect_bsap_getname,
};
int __init dect_bsap_module_init(void)
{
return dect_proto_register(&dect_bsap_proto);
}
void dect_bsap_module_exit(void)
{
dect_proto_unregister(&dect_bsap_proto);
}
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_DESCRIPTION("DECT DLC B SAP sockets");
MODULE_LICENSE("GPL");
MODULE_ALIAS_NET_PF_PROTO(PF_DECT, DECT_B_SAP);

823
net/dect/dlc_cplane.c Normal file
View File

@ -0,0 +1,823 @@
/*
* DECT DLC C-plane
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define DEBUG
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/net.h>
#include <linux/dect.h>
#include <net/dect/dect.h>
void dect_dlc_mac_page_indicate(struct dect_cluster *cl, struct sk_buff *skb)
{
dect_bsap_rcv(cl, skb);
}
static void dect_fa_parse_len(struct dect_fa_len *len, const struct sk_buff *skb)
{
u8 l;
l = skb->data[DECT_FA_LI_OFF];
len->len = (l & DECT_FA_LI_LENGTH_MASK) >> DECT_FA_LI_LENGTH_SHIFT;
len->more = (l & DECT_FA_LI_M_FLAG);
}
/*
* LAPC entity
*/
#define lapc_debug(lapc, fmt, args...) \
pr_debug("LAPC (MCEI: %u LLN: %u): " fmt, \
(lapc)->lc->mc->mcei, (lapc)->dli.lln, ## args)
static inline u8 lapc_seq_add(const struct dect_lapc *lapc, u8 s1, u8 s2)
{
return (s1 + s2) & (lapc->mod - 1);
}
static inline bool dect_fa_seq_before(const struct dect_lapc *lapc, u8 s1, u8 s2)
{
if (lapc->window == 1)
return s1 != s2;
else
return (s8)((s2 << 5) - (s1 << 5)) > 0;
}
static inline bool dect_fa_seq_after(const struct dect_lapc *lapc, u8 s1, u8 s2)
{
return dect_fa_seq_before(lapc, s2, s1);
}
/**
* dect_lapc_timeout - retransmission timer
*
* Handle missing acknowledgements:
*
* - If not already in timer recovery condition, enter it
* - otherwise add one to retransmission count
*
* If the retransmission count is below the maximum, restart the timer and
* send an "appropriate" S-frame acknowledgement or retransmit the last
* I-frame, in both cases with the poll bit set.
*/
static void dect_lapc_timeout(unsigned long data)
{
struct dect_lapc *lapc = (struct dect_lapc *)data;
struct sock *sk;
lapc_debug(lapc, "retransmission timer: cnt: %u\n", lapc->rcnt);
if (lapc->rcnt++ < DECT_LAPC_RETRANS_MAX) {
mod_timer(&lapc->timer, jiffies + DECT_LAPC_CLASS_A_ESTABLISH_TIMEOUT);
} else {
sk = lapc->sk;
sk->sk_err = ETIMEDOUT;
sk->sk_error_report(sk);
}
}
void dect_lapc_release(struct dect_lapc *lapc)
{
lapc_debug(lapc, "release\n");
if (lapc->lc->lapcs[lapc->dli.lln] != NULL)
lapc->lc->lapcs[lapc->dli.lln] = NULL;
del_timer_sync(&lapc->timer);
kfree(lapc);
}
/**
* dect_lapc_init - initialize a new LAPC entity
*/
struct dect_lapc *dect_lapc_init(const struct dect_dli *dli,
enum dect_sapis sapi,
struct dect_lc *lc, gfp_t gfp)
{
struct dect_lapc *lapc;
lapc = kzalloc(sizeof(*lapc), gfp);
if (lapc == NULL)
return NULL;
memcpy(&lapc->dli, dli, sizeof(lapc->dli));
lapc->sapi = sapi;
lapc->state = DECT_LAPC_ULI;
skb_queue_head_init(&lapc->retransq);
lapc->lc = lc;
setup_timer(&lapc->timer, dect_lapc_timeout, (unsigned long)lapc);
lapc->nlf = true;
lapc->cmd = (lc->mc->cl->mode == DECT_MODE_FP) ? true : false;
switch (lapc->dli.lln) {
case DECT_LLN_CLASS_U:
break;
case DECT_LLN_CLASS_A:
lapc->window = DECT_LAPC_CLASS_A_WINDOW;
lapc->mod = DECT_LAPC_CLASS_A_MOD;
break;
default:
lapc->window = DECT_LAPC_CLASS_B_INITIAL_WINDOW;
lapc->mod = DECT_LAPC_CLASS_B_MOD;
break;
}
lapc_debug(lapc, "init\n");
return lapc;
}
#define DECT_FA_FRAME_RESERVE 16
#define DECT_FA_FRAME_SPACE 16
static struct sk_buff *dect_lapc_alloc_skb(struct dect_lapc *lapc)
{
struct sk_buff *skb;
skb = alloc_skb(DECT_FA_FRAME_SPACE + DECT_FA_FRAME_RESERVE, GFP_ATOMIC);
if (skb == NULL)
return NULL;
skb_reset_mac_header(skb);
skb_reserve(skb, DECT_FA_FRAME_RESERVE);
skb_reserve(skb, DECT_FA_HDR_SIZE);
skb_reset_network_header(skb);
return skb;
}
static struct dect_fa_hdr *dect_prepare_fa_frame(const struct dect_lapc *lapc,
bool command,
struct sk_buff *skb)
{
struct dect_fa_hdr *fh;
u8 ilen = skb->len;
fh = (struct dect_fa_hdr *)skb_push(skb, DECT_FA_HDR_SIZE);
fh->addr = lapc->dli.lln << DECT_FA_ADDR_LLN_SHIFT;
fh->addr |= lapc->sapi << DECT_FA_ADDR_SAPI_SHIFT;
fh->addr |= DECT_FA_ADDR_RES_BIT;
fh->addr |= (command ? lapc->cmd : !lapc->cmd) ? DECT_FA_ADDR_CR_FLAG : 0;
fh->addr |= lapc->nlf ? DECT_FA_ADDR_NLF_FLAG : 0;
fh->ctrl = 0;
fh->li = ilen << DECT_FA_LI_LENGTH_SHIFT;
fh->li |= DECT_FA_LI_EXT_FLAG;
return fh;
}
static bool dect_lapc_send_iframe(struct dect_lapc *lapc, bool pf)
{
struct dect_fa_hdr *fh;
struct sk_buff *skb;
/* Window size full? */
lapc_debug(lapc, "send iframe v_a: %u window: %u v_s: %u\n",
lapc->v_a, lapc->window, lapc->v_s);
if (lapc_seq_add(lapc, lapc->v_a, lapc->window) == lapc->v_s)
return false;
/* Prepare a new I-frame */
skb = skb_dequeue(&lapc->sk->sk_write_queue);
if (skb == NULL)
return false;
fh = dect_prepare_fa_frame(lapc, true, skb);
fh->ctrl |= DECT_FA_CTRL_I_FMT_ID;
fh->ctrl |= lapc->v_r << DECT_FA_CTRL_I_NR_SHIFT;
fh->ctrl |= lapc->v_s << DECT_FA_CTRL_I_NS_SHIFT;
fh->ctrl |= pf ? DECT_FA_CTRL_I_P_FLAG : 0;
/* Append to retransmission queue and (re)start retransmission timer */
skb_queue_tail(&lapc->retransq, skb);
if (!timer_pending(&lapc->timer))
mod_timer(&lapc->timer, jiffies + DECT_LAPC_RETRANSMISSION_TIMEOUT);
lapc->v_s = lapc_seq_add(lapc, lapc->v_s, 1);
skb = skb_clone(skb, GFP_ATOMIC);
if (skb == NULL) {
/* Will be retransmitted */
return true;
}
lapc_debug(lapc, "queue I-frame v_a: %u v_r: %u v_s: %u len: %u addr: %.2x ctrl: %.2x\n",
lapc->v_a, lapc->v_r, lapc->v_s, skb->len, fh->addr, fh->ctrl);
skb_queue_tail(&lapc->lc->txq, skb);
return true;
}
/*
* Send a S-frame with the specified command. The command/response bit setting
* depends on the role of the LAPC, a PP uses 0 for commands and 1 for responses,
* a FT 1 for commands and 0 for responses.
*/
static bool dect_lapc_send_sframe(struct dect_lapc *lapc, u8 cr,
bool command, bool pf)
{
struct dect_fa_hdr *fh;
struct sk_buff *skb;
skb = dect_lapc_alloc_skb(lapc);
if (skb == NULL)
return false;
fh = dect_prepare_fa_frame(lapc, command, skb);
fh->ctrl |= DECT_FA_CTRL_S_FMT_ID;
fh->ctrl |= lapc->v_r << DECT_FA_CTRL_S_NR_SHIFT;
fh->ctrl |= cr;
fh->ctrl |= pf ? DECT_FA_CTRL_S_PF_FLAG : 0;
lapc_debug(lapc, "queue S-frame v_r: %u len: %u addr: %.2x ctrl: %.2x\n",
lapc->v_r, skb->len, fh->addr, fh->ctrl);
skb_queue_tail(&lapc->lc->txq, skb);
lapc->nlf = false;
return true;
}
/*
* Send an acknowledgement frame. Class B entities use RNR responses to indicate
* their status while busy. Otherwise an I-frame is used when data is available
* and a RR response frame otherwise.
*/
static void dect_lapc_send_ack(struct dect_lapc *lapc, bool pf)
{
lapc_debug(lapc, "send ACK I-frame present: %u\n",
skb_peek(&lapc->sk->sk_write_queue) ? 1 : 0);
if (lapc->dli.lln != DECT_LLN_CLASS_A && lapc->busy)
dect_lapc_send_sframe(lapc, DECT_FA_CTRL_S_CR_RNR, false, false);
else if (!lapc->peer_busy && skb_peek(&lapc->sk->sk_write_queue))
dect_lapc_send_iframe(lapc, pf);
else
dect_lapc_send_sframe(lapc, DECT_FA_CTRL_S_CR_RR, false, pf);
}
static void dect_lapc_queue_data(struct dect_lapc *lapc, struct sk_buff *skb)
{
struct dect_fa_hdr *fh = (struct dect_fa_hdr *)skb->data;
skb_pull(skb, DECT_FA_HDR_SIZE);
if (skb->len == 0) {
kfree_skb(skb);
return;
}
lapc_debug(lapc, "reassemble: segment len %u more %u\n",
skb->len, (fh->li & DECT_FA_LI_M_FLAG) ? 1 : 0);
lapc->rcv_head = skb_append_frag(lapc->rcv_head, skb);
if (!(fh->li & DECT_FA_LI_M_FLAG)) {
skb = lapc->rcv_head;
lapc->rcv_head = NULL;
lapc_debug(lapc, "reassembled: message len %u\n", skb->len);
sock_queue_rcv_skb(lapc->sk, skb);
}
}
static bool dect_lapc_update_ack(struct dect_lapc *lapc, u8 seq)
{
u8 v_a = lapc->v_a;
lapc_debug(lapc, "update ACK: v_a: %u v_s: %u seq: %u\n",
lapc->v_a, lapc->v_s, seq);
lapc_debug(lapc, "seq %u after v_a %u: %u\n", seq, lapc->v_a,
dect_fa_seq_after(lapc, seq, lapc->v_a));
lapc_debug(lapc, "v_s %u !after seq %u: %u\n", lapc->v_s, seq,
!dect_fa_seq_after(lapc, lapc->v_s, seq));
/* If all outstanding I-frames have been acknowledged, stop
* retransmission timer, otherwise reset it.
*/
if (dect_fa_seq_after(lapc, seq, lapc->v_a) &&
!dect_fa_seq_after(lapc, lapc->v_s, seq)) {
lapc->v_a = seq;
if (lapc->v_a == lapc->v_s)
del_timer_sync(&lapc->timer);
else
mod_timer(&lapc->timer, jiffies + DECT_LAPC_RETRANSMISSION_TIMEOUT);
} else if (seq != lapc->v_a)
return false;
/* Purge acknowledged frames from transmit queue */
while (v_a != lapc->v_a) {
lapc_debug(lapc, "purge retransmit queue seq: %u\n", v_a);
kfree_skb(skb_dequeue(&lapc->retransq));
v_a = lapc_seq_add(lapc, v_a, 1);
}
return true;
}
/*
* Receive a Class A or Class B I-frame. Frames with valid sequence numbers
* are acknowledged and queued for segment reassembly. Invalid sequence
* numbers cause an ACK with the expected sequence number to be sent.
*
* Class B entities need to indicate their receiver busy status when busy or
* when explicitly polled.
*/
static void dect_lapc_rcv_iframe(struct dect_lapc *lapc, struct sk_buff *skb)
{
struct dect_fa_hdr *fh = (struct dect_fa_hdr *)skb->data;
bool poll = false;
u8 n_s, n_r, res;
if (lapc->dli.lln == DECT_LLN_CLASS_U) {
kfree_skb(skb);
return;
}
n_r = (fh->ctrl & DECT_FA_CTRL_I_NR_MASK) >> DECT_FA_CTRL_I_NR_SHIFT;
n_s = (fh->ctrl & DECT_FA_CTRL_I_NS_MASK) >> DECT_FA_CTRL_I_NS_SHIFT;
if (lapc->dli.lln != DECT_LLN_CLASS_A)
poll = fh->ctrl & DECT_FA_CTRL_I_P_FLAG;
lapc_debug(lapc, "receive I-frame: n_r: %u n_s: %u poll: %u\n",
n_r, n_s, poll);
dect_lapc_update_ack(lapc, n_r);
/* While in receiver busy condition, all I-frames are dropped after
* updating the acknowledgement number. In Class B mode receiver status
* queries are still answered.
*/
if (lapc->busy) {
kfree_skb(skb);
if (poll)
goto poll;
return;
}
/* When the frame contains an invalid sequence number, send an
* immediate ACK. */
if (n_s != lapc->v_r) {
lapc_debug(lapc, "invalid sequence number %u %u\n", n_s, lapc->v_r);
kfree_skb(skb);
goto ack;
}
lapc->v_r = lapc_seq_add(lapc, lapc->v_r, 1);
dect_lapc_queue_data(lapc, skb);
if (poll)
goto poll;
ack:
return dect_lapc_send_ack(lapc, poll);
poll:
res = lapc->busy ? DECT_FA_CTRL_S_CR_RNR : DECT_FA_CTRL_S_CR_RR;
dect_lapc_send_sframe(lapc, res, false, true);
}
static void dect_lapc_rcv_sframe(struct dect_lapc *lapc, struct sk_buff *skb)
{
struct dect_fa_hdr *fh = (struct dect_fa_hdr *)skb->data;
bool pf;
u8 n_r;
n_r = (fh->ctrl & DECT_FA_CTRL_S_NR_MASK) >> DECT_FA_CTRL_S_NR_SHIFT;
pf = (fh->ctrl & DECT_FA_CTRL_S_PF_FLAG);
lapc_debug(lapc, "receive S-frame: n_r: %u pf: %u\n", n_r, pf);
switch (fh->ctrl & DECT_FA_CTRL_S_CR_MASK) {
case DECT_FA_CTRL_S_CR_RR:
if (!dect_lapc_update_ack(lapc, n_r))
goto err;
if (lapc->lc->elapc == lapc) {
/* Connection establishment completed */
lapc_debug(lapc, "established\n");
lapc->lc->elapc = NULL;
del_timer_sync(&lapc->timer);
lapc->sk->sk_state = DECT_SK_ESTABLISHED;
lapc->sk->sk_state_change(lapc->sk);
}
dect_lapc_send_iframe(lapc, pf);
break;
case DECT_FA_CTRL_S_CR_RNR:
/*
* Note peer receiver busy condition. If it was a RNR command
* with the P bit set to 1, send a RR response with the F bit
* set to 1. If it was a RNR response with the F bit set to 1,
* clear timer recovery condition and update V(S).
*/
lapc->peer_busy = true;
if (fh->addr & DECT_FA_ADDR_CR_FLAG && pf)
dect_lapc_send_sframe(lapc, DECT_FA_CTRL_S_CR_RR, true, true);
else if (!(fh->addr & DECT_FA_ADDR_CR_FLAG) && pf) {
del_timer_sync(&lapc->timer);
lapc->v_s = n_r;
}
dect_lapc_update_ack(lapc, n_r);
break;
case DECT_FA_CTRL_S_CR_REJ:
lapc->peer_busy = false;
lapc->v_s = n_r;
lapc->v_a = n_r;
del_timer_sync(&lapc->timer);
break;
default:
goto err;
}
err:
kfree_skb(skb);
}
static void dect_lapc_rcv_uframe(struct dect_lapc *lapc, struct sk_buff *skb)
{
struct dect_fa_hdr *fh = (struct dect_fa_hdr *)skb->data;
u8 pf, cr;
pf = (fh->ctrl & DECT_FA_CTRL_U_PF_FLAG);
cr = (fh->ctrl & DECT_FA_CTRL_U_U1_MASK) |
(fh->ctrl & DECT_FA_CTRL_U_CR_MASK);
/* unnumbered information is only valid in class U mode */
if (cr == DECT_FA_CTRL_U_CR_UI) {
if (lapc->dli.lln != DECT_LLN_CLASS_U)
goto err;
lapc_debug(lapc, "queue UI message len: %u\n", skb->len);
sock_queue_rcv_skb(lapc->sk, skb);
return;
}
/* the remaining commands/responses are only valid in class B mode */
if (lapc->dli.lln == DECT_LLN_CLASS_A)
goto err;
switch (cr) {
case DECT_FA_CTRL_U_CR_SABM:
break;
case DECT_FA_CTRL_U_CR_DM:
break;
case DECT_FA_CTRL_U_CR_DISC:
break;
case DECT_FA_CTRL_U_CR_UA:
break;
}
err:
kfree_skb(skb);
}
static void dect_lapc_rcv(struct dect_lapc *lapc, struct sk_buff *skb)
{
struct dect_fa_hdr *fh = (struct dect_fa_hdr *)skb->data;
if ((fh->ctrl & DECT_FA_CTRL_I_FMT_MASK) == DECT_FA_CTRL_I_FMT_ID)
return dect_lapc_rcv_iframe(lapc, skb);
else if ((fh->ctrl & DECT_FA_CTRL_S_FMT_MASK) == DECT_FA_CTRL_S_FMT_ID)
return dect_lapc_rcv_sframe(lapc, skb);
else if ((fh->ctrl & DECT_FA_CTRL_U_FMT_MASK) == DECT_FA_CTRL_U_FMT_ID)
return dect_lapc_rcv_uframe(lapc, skb);
else
kfree_skb(skb);
}
int dect_lapc_transmit(struct dect_lapc *lapc)
{
dect_lapc_send_iframe(lapc, 0);
return 0;
}
int dect_lapc_establish(struct dect_lapc *lapc)
{
struct sk_buff *skb;
lapc_debug(lapc, "establish\n");
/* Prepend zero-sized message to transmit queue to trigger connection
* establishment.
*/
skb = dect_lapc_alloc_skb(lapc);
if (skb == NULL)
return -ENOMEM;
skb_queue_head(&lapc->sk->sk_write_queue, skb);
lapc->lc->elapc = lapc;
dect_lapc_send_iframe(lapc, lapc->dli.lln != DECT_LLN_CLASS_A);
lapc->nlf = false;
mod_timer(&lapc->timer, jiffies + DECT_LAPC_CLASS_A_ESTABLISH_TIMEOUT);
return 0;
}
/*
* Lc entity
*
* The Lc entity receives and transmits LAPC frames from/to the MAC layer.
*
* For transmission the frames are checksummed and fragmented into channel
* sized units. The channel is chosen before transmission of a new frame
* based on availability and demand. All fragments of one frame are
* transmitted in the chosen channel.
*
* Received fragments are resegmented and have their checksum validated,
* then routed to the LAPC entity associated with the logical link number.
*/
#define lc_debug(lc, fmt, args...) \
pr_debug("Lc (MCEI %x): " fmt, (lc)->mc->mcei, ## args)
void dect_lc_release(struct dect_lc *lc)
{
kfree_skb(lc->rx_head);
kfree_skb(lc->tx_head);
__skb_queue_purge(&lc->txq);
kfree(lc);
}
struct dect_lc *dect_lc_init(struct dect_mac_conn *mc, gfp_t gfp)
{
struct dect_lc *lc;
lc = kzalloc(sizeof(*lc), gfp);
if (lc == NULL)
return NULL;
lc->mc = mc;
lc_debug(lc, "init\n");
skb_queue_head_init(&lc->txq);
switch (mc->mci.pmid.type) {
case DECT_PMID_ASSIGNED:
lc->lsig = htons(dect_build_pmid(&mc->mci.pmid) >> 4);
break;
default:
lc->lsig = 0;
break;
}
return lc;
}
static void dect_fa_frame_csum(const struct dect_lc *lc, struct sk_buff *skb)
{
u8 *data = skb->data;
unsigned int i;
u8 c0 = 0, c1 = 0;
u8 x, y;
u16 t;
data[skb->len - 2] = 0;
data[skb->len - 1] = 0;
for (i = 0; i < skb->len; i++) {
t = c0 + data[i];
c0 = (t & 0xffU) + ((t >> 8) & 0x1U);
t = c1 + c0;
c1 = (t & 0xffU) + ((t >> 8) & 0x1U);
}
t = c0 + (u8)~c1;
x = (t & 0xffU) + ((t >> 8) & 0x1U);
t = (u8)~c0 + (u8)~c0;
t = (t & 0xffU) + ((t >> 8) & 0x1U);
t += c1;
y = (t & 0xffU) + ((t >> 8) & 0x1U);
data[skb->len - 2] = x ^ (lc->lsig >> 8);
data[skb->len - 1] = y ^ (lc->lsig & 0xff);
lc_debug(lc, "checksum: lsig: %.4x x: %.2x y: %.2x\n",
lc->lsig, x, y);
}
static bool dect_fa_frame_csum_verify(const struct dect_lc *lc,
struct sk_buff *skb)
{
u8 *data = skb->data;
unsigned int i;
u8 c0 = 0, c1 = 0;
u16 t;
data[skb->len - 2] ^= lc->lsig >> 8;
data[skb->len - 1] ^= lc->lsig & 0xff;
for (i = 0; i < skb->len; i++) {
t = c0 + data[i];
c0 = (t & 0xffU) + ((t >> 8) & 0x1U);
t = c1 + c0;
c1 = (t & 0xffU) + ((t >> 8) & 0x1U);
}
lc_debug(lc, "csum verify: lsig %.4x c0: %.2x c1: %.2x\n",
lc->lsig, c0, c1);
return c0 == (u8)~0 && c1 == (u8)~0;
}
static const u8 channel_sdu_size[] = {
[DECT_MC_C_S] = DECT_C_S_SDU_SIZE,
[DECT_MC_C_F] = DECT_C_F_SDU_SIZE,
};
/*
* Prepare a DLC frame for transmission to the MAC layer. This involves
* checksumming the frame, selecting the logical channel for transmission
* and fragmenting it into units carried by the logical channel.
*/
static struct sk_buff *dect_lc_tx(struct dect_lc *lc)
{
struct sk_buff *skb, *frag;
u8 *fill, fill_len;
u8 flen;
skb = lc->tx_head;
if (skb == NULL) {
skb = skb_dequeue(&lc->txq);
if (skb == NULL)
return NULL;
lc_debug(lc, "tx: begin new frame len: %u\n", skb->len);
flen = channel_sdu_size[DECT_MC_C_S];
fill_len = roundup(skb->len + DECT_FA_CSUM_SIZE, flen) -
(skb->len + DECT_FA_CSUM_SIZE);
fill = skb_put(skb, fill_len);
memset(fill, DECT_FA_FILL_PATTERN, fill_len);
skb_put(skb, DECT_FA_CSUM_SIZE);
dect_fa_frame_csum(lc, skb);
WARN_ON(!dect_fa_frame_csum_verify(lc, skb));
lc->tx_head = skb;
lc->tx_len = flen;
}
/* Fragment into tx_len sized units */
if (skb->len > lc->tx_len) {
frag = skb_copy(skb, GFP_ATOMIC);
if (frag == NULL)
return NULL;
skb_trim(frag, lc->tx_len);
skb_pull(skb, lc->tx_len);
} else {
frag = lc->tx_head;
lc->tx_head = NULL;
}
lc_debug(lc, "tx: %sfragment len: %u\n",
lc->tx_head ? "" : "last ", frag->len);
{ unsigned int i; for (i = 0; i< frag->len; i++) printk("%.2x ", frag->data[i]);
printk("\n");}
return frag;
}
static struct sk_buff *dect_lc_reassemble(struct dect_lc *lc,
enum dect_data_channels chan,
struct sk_buff *skb)
{
struct dect_fa_len fl;
u8 flen, len;
if (lc->rx_head == NULL) {
dect_fa_parse_len(&fl, skb);
len = fl.len;
len += DECT_FA_HDR_SIZE + DECT_FA_CSUM_SIZE;
flen = channel_sdu_size[chan];
lc->rx_len = roundup(len, flen);
}
lc->rx_head = skb_append_frag(lc->rx_head, skb);
skb = NULL;
if (lc->rx_head->len >= lc->rx_len) {
WARN_ON(lc->rx_head->len != lc->rx_len);
skb = lc->rx_head;
lc->rx_head = NULL;
if (skb_linearize(skb) < 0)
goto err;
if (!dect_fa_frame_csum_verify(lc, skb))
goto err;
/* Trim checksum and filling */
dect_fa_parse_len(&fl, skb);
skb_trim(skb, fl.len + DECT_FA_HDR_SIZE);
lc_debug(lc, "reassembled SDU len %u\n", skb->len);
}
return skb;
err:
lc_debug(lc, "reassembly failed\n");
kfree_skb(skb);
return NULL;
}
static void dect_lc_rcv(struct dect_lc *lc, enum dect_data_channels chan,
struct sk_buff *skb)
{
struct dect_fa_hdr *fh;
struct dect_lapc *lapc;
struct dect_dli dli;
enum dect_sapis sapi;
skb = dect_lc_reassemble(lc, chan, skb);
if (skb == NULL)
return;
fh = (struct dect_fa_hdr *)skb->data;
dli.lln = (fh->addr & DECT_FA_ADDR_LLN_MASK) >> DECT_FA_ADDR_LLN_SHIFT;
lc_debug(lc, "receive: LLN %u NLF %u SAPI %u\n",
dli.lln, (fh->addr & DECT_FA_ADDR_NLF_FLAG) ? 1 : 0,
(fh->addr & DECT_FA_ADDR_SAPI_MASK) >> DECT_FA_ADDR_SAPI_SHIFT);
if (lc->lapcs[dli.lln] != NULL)
return dect_lapc_rcv(lc->lapcs[dli.lln], skb);
/* Link establishment: new requests are only valid while no link
* estabishment is in progress.
*/
if (!(fh->addr & DECT_FA_ADDR_NLF_FLAG))
goto err;
if ((fh->ctrl & DECT_FA_CTRL_I_FMT_MASK) != DECT_FA_CTRL_I_FMT_ID)
goto err;
if (lc->elapc != NULL)
goto err;
sapi = (fh->addr & DECT_FA_ADDR_SAPI_MASK) >> DECT_FA_ADDR_SAPI_SHIFT;
if (sapi != DECT_SAPI_CO_SIGNALLING && sapi != DECT_SAPI_CL_SIGNALLING)
goto err;
memcpy(&dli.mci, &lc->mc->mci, sizeof(dli.mci));
lapc = dect_ssap_rcv_request(lc, &dli, sapi);
if (lapc == NULL)
goto err;
lc->lapcs[dli.lln] = lapc;
return dect_lapc_rcv(lapc, skb);
err:
lc_debug(lc, "packet ignored\n");
kfree_skb(skb);
}
void dect_cplane_rcv(struct dect_mac_conn *mc, enum dect_data_channels chan,
struct sk_buff *skb)
{
struct dect_fa_hdr *fh = (struct dect_fa_hdr *)skb->data;
struct dect_lc *lc;
if (mc->lc == NULL) {
#if 0
if (!(fh->addr & DECT_FA_ADDR_NLF_FLAG))
goto err;
#endif
lc = dect_lc_init(mc, GFP_ATOMIC);
if (lc == NULL)
goto err;
mc->lc = lc;
}
return dect_lc_rcv(mc->lc, chan, skb);
err:
kfree_skb(skb);
}
struct sk_buff *dect_cplane_dtr(struct dect_mac_conn *mc, enum dect_data_channels chan)
{
struct dect_lc *lc;
lc = mc->lc;
if (lc == NULL)
return NULL;
lc_debug(lc, "DTR channel %u\n", chan);
return dect_lc_tx(lc);
}
void dect_cplane_notify_state_change(struct dect_mac_conn *mc)
{
struct dect_lc *lc = mc->lc;
unsigned int i;
if (lc == NULL)
return;
lc_debug(lc, "mac conn state change: state: %u\n", mc->state);
switch (mc->state) {
// FIXME: this does not make sense for incoming connections
case DECT_MAC_CONN_OPEN_PENDING:
break;
case DECT_MAC_CONN_OPEN:
for (i = 0; i < ARRAY_SIZE(lc->lapcs); i++) {
if (lc->lapcs[i] == NULL)
continue;
dect_lapc_establish(lc->lapcs[i]);
break;
}
break;
case DECT_MAC_CONN_CLOSED:
for (i = 0; i < ARRAY_SIZE(lc->lapcs); i++) {
if (lc->lapcs[i] == NULL)
continue;
break;
}
break;
}
}

52
net/dect/dlc_fbx.c Normal file
View File

@ -0,0 +1,52 @@
/*
* DECT DLC Layer
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
static void dect_dlc_fb1_enqueue(struct dect_dlc_fbx *fbx, struct sk_buff *skb)
{
struct dect_dlc_lux *lux = container_of(fbx, struct dect_dlc_lux, fbx);
struct sock *sk = &lux->sk;
skb_queue_tail(&sk->sk_write_queue, skb);
}
static struct sk_buff *dect_dlc_fb1_dequeue(struct dect_dlc_fbx *fbx)
{
struct dect_dlc_lux *lux = container_of(fbx, struct dect_dlc_lux, fbx);
struct sock *sk = &lux->sk;
struct sk_buff *skb, *clone, *head = NULL;
int need = 40;
while (need > 0) {
skb = skb_peek(&sk->sk_write_queue);
if (skb == NULL)
goto err;
if (skb->len <= need) {
__skb_unlink(skb, &sk->sk_write_queue);
need -= skb->len;
} else {
clone = skb_clone(skb, GFP_ATOMIC);
if (clone == NULL)
goto err;
clone->len = need;
skb_pull(skb, need);
skb = clone;
}
head = skb_append_frag(head, skb);
}
return head;
err:
return NULL;
}
const struct dect_dlc_fbx_ops dect_dlc_fb1_ops = {
.enqueue = dect_dlc_fb1_enqueue,
.dequeue = dect_dlc_fb1_dequeue,
};

286
net/dect/dlc_lu1_sap.c Normal file
View File

@ -0,0 +1,286 @@
/*
* DECT DLC LU1 SAP sockets
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/dect.h>
#include <net/sock.h>
#include <net/dect/dect.h>
struct dect_lu1_sap {
struct sock sk;
struct dect_ulei ulei;
struct dect_mac_conn *mc;
struct dect_lux lux;
};
static struct sk_buff *dect_lu1_dequeue(struct dect_lux *lux)
{
struct dect_lu1_sap *lu1 = container_of(lux, struct dect_lu1_sap, lux);
return skb_dequeue(&lu1->sk.sk_write_queue);
}
static void dect_lu1_enqueue(struct dect_lux *lux, struct sk_buff *skb)
{
struct dect_lu1_sap *lu1 = container_of(lux, struct dect_lu1_sap, lux);
if (sock_queue_rcv_skb(&lu1->sk, skb) < 0)
kfree_skb(skb);
}
static void dect_lu1_disconnect(struct dect_lux *lux)
{
struct dect_lu1_sap *lu1 = container_of(lux, struct dect_lu1_sap, lux);
struct sock *sk = &lu1->sk;
sk->sk_state = DECT_SK_RELEASED;
sk->sk_err = ENETDOWN;
if (!sock_flag(sk, SOCK_DEAD))
sk->sk_error_report(sk);
lu1->mc = NULL;
}
static const struct dect_lux_ops dect_lu1_ops = {
.dequeue = dect_lu1_dequeue,
.enqueue = dect_lu1_enqueue,
.disconnect = dect_lu1_disconnect,
};
static inline struct dect_lu1_sap *dect_lu1_sap(struct sock *sk)
{
return (struct dect_lu1_sap *)sk;
}
static int dect_parse_ulei(struct dect_ulei *ulei,
const struct sockaddr_dect_lu *addr)
{
if (dect_parse_ari(&ulei->mci.ari, (u64)addr->dect_ari << 24) == 0)
return -EINVAL;
dect_parse_pmid(&ulei->mci.pmid, addr->dect_pmid);
ulei->mci.lcn = addr->dect_lcn;
return 0;
}
static void dect_build_ulei(struct sockaddr_dect_lu *addr,
const struct dect_ulei *ulei)
{
addr->dect_family = AF_DECT;
addr->dect_pmid = dect_build_pmid(&ulei->mci.pmid);
addr->dect_lcn = ulei->mci.lcn;
}
static int dect_lu1_init(struct sock *sk)
{
sk->sk_state = DECT_SK_RELEASED;
return 0;
}
static void dect_lu1_close(struct sock *sk, long timeout)
{
struct dect_lu1_sap *lu1 = dect_lu1_sap(sk);
if (sk->sk_state == DECT_SK_ESTABLISHED) {
lu1->mc->fbx = NULL;
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
}
__skb_queue_purge(&sk->sk_receive_queue);
__skb_queue_purge(&sk->sk_write_queue);
sock_put(sk);
}
static int dect_lu1_getname(struct sock *sk, struct sockaddr *uaddr,
int *len, int peer)
{
struct sockaddr_dect_lu *addr = (struct sockaddr_dect_lu *)uaddr;
struct dect_lu1_sap *lu1 = dect_lu1_sap(sk);
if (peer)
return -EOPNOTSUPP;
dect_build_ulei(addr, &lu1->ulei);
*len = sizeof(*addr);
return 0;
}
static int dect_lu1_connect(struct sock *sk, struct sockaddr *uaddr, int len)
{
struct sockaddr_dect_lu *addr = (struct sockaddr_dect_lu *)uaddr;
struct dect_lu1_sap *lu1 = dect_lu1_sap(sk);
struct dect_cluster *cl;
struct dect_ulei ulei;
struct dect_mac_conn *mc;
int err;
err = dect_parse_ulei(&ulei, addr);
if (err < 0)
goto err1;
err = -ENODEV;
cl = dect_cluster_get_by_pari(&ulei.mci.ari);
if (cl == NULL)
goto err1;
err = -ENETDOWN;
mc = dect_mac_conn_get_by_mci(cl, &ulei.mci);
if (mc == NULL)
goto err1;
err = -EBUSY;
if (mc->fbx != NULL)
goto err1;
memcpy(&lu1->ulei, &ulei, sizeof(lu1->ulei));
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
sk->sk_state = DECT_SK_ESTABLISHED;
lu1->lux.fbx.ops = &dect_fbn_ops;
lu1->lux.ops = &dect_lu1_ops;
lu1->mc = mc;
mc->fbx = &lu1->lux.fbx;
printk("LU1: bound to MCEI %u\n", mc->mcei);
return 0;
err1:
return err;
}
static int dect_lu1_recvmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, size_t len,
int noblock, int flags, int *addr_len)
{
struct sk_buff *skb;
size_t copied = 0, copy;
long timeo;
int err;
if (flags & (MSG_OOB | MSG_TRUNC))
return -EOPNOTSUPP;
lock_sock(sk);
if (sk->sk_state != DECT_SK_ESTABLISHED) {
err = -ENOTCONN;
goto out;
}
timeo = sock_rcvtimeo(sk, noblock);
do {
skb = skb_peek(&sk->sk_receive_queue);
if (skb != NULL)
goto copy;
if (!timeo) {
err = -EAGAIN;
break;
}
if (signal_pending(current)) {
err = sock_intr_errno(timeo);
break;
}
sk_wait_data(sk, &timeo);
continue;
copy:
copy = len - copied;
if (copy > skb->len)
copy = skb->len;
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copy);
if (err < 0)
break;
copied += copy;
if (copy < skb->len) {
__skb_pull(skb, copy);
break;
} else
sk_eat_skb(sk, skb, 0);
} while (1);
out:
printk("LU1: %p: recv err %d copied %zu\n", sk, err, copied);
release_sock(sk);
return copied ? : err;
}
static int dect_lu1_sendmsg(struct kiocb *kiocb, struct sock *sk,
struct msghdr *msg, size_t len)
{
struct sk_buff *skb;
int err;
if (msg->msg_flags & MSG_OOB)
return -EOPNOTSUPP;
if (sk->sk_state != DECT_SK_ESTABLISHED)
return -ENOTCONN;
skb = sock_alloc_send_skb(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);
if (skb == NULL)
goto err1;
err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
if (err < 0)
goto err2;
skb_queue_tail(&sk->sk_write_queue, skb);
return len;
err2:
kfree_skb(skb);
err1:
printk("LU1: %p: send err %d wmem %u\n", sk, err, atomic_read(&sk->sk_wmem_alloc));
return err;
}
static struct dect_proto dect_lu1_proto = {
.type = SOCK_STREAM,
.protocol = DECT_LU1_SAP,
.capability = -1,
.ops = &dect_stream_ops,
.proto.name = "DECT_LU1_SAP",
.proto.owner = THIS_MODULE,
.proto.obj_size = sizeof(struct dect_lu1_sap),
.proto.init = dect_lu1_init,
.proto.close = dect_lu1_close,
.proto.connect = dect_lu1_connect,
.proto.recvmsg = dect_lu1_recvmsg,
.proto.sendmsg = dect_lu1_sendmsg,
.getname = dect_lu1_getname,
};
int __init dect_lu1_sap_module_init(void)
{
return dect_proto_register(&dect_lu1_proto);
}
void dect_lu1_sap_module_exit(void)
{
dect_proto_unregister(&dect_lu1_proto);
}
#if 0
module_init(dect_lu1_init);
module_exit(dect_lu1_exit);
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_DESCRIPTION("DECT DLC LU1 SAP sockets");
MODULE_LICENSE("GPL");
#endif
MODULE_ALIAS_NET_PF_PROTO(PF_DECT, DECT_LU1);

564
net/dect/dlc_s_sap.c Normal file
View File

@ -0,0 +1,564 @@
/*
* DECT DLC S SAP sockets - DLC C-plane data link service access
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define DEBUG
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/dect.h>
#include <net/sock.h>
#include <net/dect/dect.h>
static DEFINE_SPINLOCK(dect_ssap_lock);
static HLIST_HEAD(dect_ssap_sockets);
static HLIST_HEAD(dect_ssap_listeners);
#define DECT_LLN_ANY 255
struct dect_ssap {
struct dect_csk csk;
struct dect_dlei dlei;
struct dect_lapc *lapc;
};
static inline struct dect_ssap *dect_ssap(struct sock *sk)
{
return (struct dect_ssap *)sk;
}
static int dect_parse_dlei(struct dect_dlei *dlei,
const struct sockaddr_dect_ssap *addr)
{
if (dect_parse_ari(&dlei->mci.ari, (u64)addr->dect_ari << 24) == 0)
return -EINVAL;
dect_parse_pmid(&dlei->mci.pmid, addr->dect_pmid);
dlei->mci.lcn = addr->dect_lcn;
dlei->lln = addr->dect_lln;
if (dlei->lln > DECT_LLN_MAX)
return -EINVAL;
dlei->sapi = addr->dect_sapi;
switch (dlei->sapi) {
case DECT_SAPI_CO_SIGNALLING:
case DECT_SAPI_CL_SIGNALLING:
break;
default:
return -EINVAL;
}
return 0;
}
static void dect_build_dlei(struct sockaddr_dect_ssap *addr,
const struct dect_dlei *dlei)
{
addr->dect_family = AF_DECT;
addr->dect_pmid = dect_build_pmid(&dlei->mci.pmid);
addr->dect_ari = dect_build_ari(&dlei->mci.ari) >> 24;
addr->dect_lcn = dlei->mci.lcn;
addr->dect_lln = dlei->lln;
addr->dect_sapi = dlei->sapi;
}
static void dect_ssap_insert(struct sock *sk)
{
sk_add_node(sk, &dect_ssap_sockets);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
}
static void dect_ssap_unlink(struct sock *sk)
{
if (sk_del_node_init(sk))
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
}
static int dect_ssap_init(struct sock *sk)
{
struct dect_ssap *ssap = dect_ssap(sk);
INIT_HLIST_HEAD(&ssap->csk.accept_queue);
return 0;
}
static struct sock *dect_ssap_acceptq_dequeue(struct dect_ssap *ssap)
{
struct sock *sk;
if (hlist_empty(&ssap->csk.accept_queue))
return NULL;
sk = hlist_entry(ssap->csk.accept_queue.first, struct sock, sk_bind_node);
__sk_del_bind_node(sk);
sk_node_init(&sk->sk_bind_node);
sk_acceptq_removed(&ssap->csk.sk);
return sk;
}
static void dect_ssap_close(struct sock *sk, long timeout)
{
struct dect_ssap *ssap = dect_ssap(sk);
struct sock *req;
printk("close sock %p\n", sk);
dect_ssap_unlink(sk);
if (ssap->lapc != NULL) {
sock_put(ssap->lapc->sk);
dect_lapc_release(ssap->lapc);
}
if (!hlist_unhashed(&sk->sk_bind_node))
__sk_del_bind_node(sk);
while ((req = dect_ssap_acceptq_dequeue(ssap)) != NULL) {
dect_ssap_unlink(req);
dect_lapc_release(dect_ssap(req)->lapc);
sock_put(req);
}
sk_common_release(sk);
}
static int dect_ssap_bind_conflict(const struct dect_dlei *dlei)
{
struct dect_ssap *ssap;
struct hlist_node *n;
struct sock *sk;
// FIXME: wildcards
sk_for_each(sk, n, &dect_ssap_sockets) {
ssap = dect_ssap(sk);
if (!dect_pmid_cmp(&ssap->dlei.mci.pmid, &dlei->mci.pmid) &&
ssap->dlei.lln == dlei->lln)
return -EADDRINUSE;
}
return 0;
}
static int dect_ssap_bind(struct sock *sk, struct sockaddr *uaddr, int len)
{
struct sockaddr_dect_ssap *addr = (struct sockaddr_dect_ssap *)uaddr;
struct dect_ssap *ssap = dect_ssap(sk);
struct dect_dlei dlei;
int err;
if (len < sizeof(*addr) || addr->dect_family != AF_DECT)
return -EINVAL;
err = dect_parse_dlei(&dlei, addr);
if (err < 0)
return err;
lock_sock(sk);
spin_lock_bh(&dect_ssap_lock);
err = dect_ssap_bind_conflict(&dlei);
if (err < 0)
goto out;
memcpy(&ssap->dlei, &dlei, sizeof(ssap->dlei));
dect_ssap_insert(sk);
out:
spin_unlock_bh(&dect_ssap_lock);
release_sock(sk);
return err;
}
static struct dect_ssap *dect_ssap_lookup_listener(const struct dect_dli *dli,
enum dect_sapis sapi)
{
struct dect_ssap *ssap;
struct hlist_node *n;
struct sock *sk;
pr_debug("lookup listener: lln %u sapi %u\n", dli->lln, sapi);
sk_for_each_bound(sk, n, &dect_ssap_listeners) {
ssap = dect_ssap(sk);
#if 0
if (!dect_ari_cmp(&ssap->dlei.mci.ari, &dli->mci.ari))
continue;
if (!dect_pmid_cmp(&ssap->dlei.mci.pmid, &dli->mci.pmid))
continue;
#endif
pr_debug("ssap: lln %u sapi %u\n", ssap->dlei.lln, ssap->dlei.sapi);
if (ssap->dlei.lln != DECT_LLN_ANY &&
ssap->dlei.lln != dli->lln)
continue;
if (ssap->dlei.sapi != sapi)
continue;
return ssap;
}
return NULL;
}
struct dect_lapc *dect_ssap_rcv_request(struct dect_lc *lc,
const struct dect_dli *dli,
enum dect_sapis sapi)
{
struct dect_ssap *ssap, *newssap;
struct sock *sk, *newsk;
struct dect_lapc *lapc = NULL;
spin_lock(&dect_ssap_lock);
ssap = dect_ssap_lookup_listener(dli, sapi);
if (ssap == NULL)
goto out;
sk = &ssap->csk.sk;
if (sk_acceptq_is_full(sk))
goto out;
newsk = sk_alloc(&init_net, PF_DECT, GFP_ATOMIC, sk->sk_prot);
if (newsk == NULL)
goto out;
lapc = dect_lapc_init(dli, sapi, lc, GFP_ATOMIC);
if (lapc == NULL)
goto err1;
sock_hold(newsk);
lapc->sk = newsk;
sock_init_data(NULL, newsk);
newsk->sk_protocol = sk->sk_protocol;
newsk->sk_destruct = sk->sk_destruct;
newssap = dect_ssap(newsk);
memcpy(&newssap->dlei.mci, &dli->mci, sizeof(newssap->dlei.mci));
newssap->dlei.lln = dli->lln;
newssap->dlei.sapi = sapi;
newssap->lapc = lapc;
newsk->sk_state = DECT_SK_ESTABLISHED;
dect_ssap_insert(newsk);
sk_add_bind_node(newsk, &ssap->csk.accept_queue);
sk_acceptq_added(sk);
sk->sk_state_change(sk);
sk->sk_data_ready(sk, 0);
out:
spin_unlock(&dect_ssap_lock);
return lapc;
err1:
sk_free(sk);
goto out;
}
static void dect_ssap_hash(struct sock *sk)
{
sk->sk_state = DECT_SK_LISTEN;
spin_lock_bh(&dect_ssap_lock);
sk_add_bind_node(sk, &dect_ssap_listeners);
spin_unlock_bh(&dect_ssap_lock);
}
static void dect_ssap_unhash(struct sock *sk)
{
if (sk_hashed(sk)) {
spin_lock_bh(&dect_ssap_lock);
__sk_del_bind_node(sk);
spin_unlock_bh(&dect_ssap_lock);
}
}
static int dect_ssap_wait_req(struct sock *sk, int noblock)
{
struct task_struct *tsk = current;
struct dect_ssap *ssap = dect_ssap(sk);
long timeo = sock_rcvtimeo(sk, noblock);
for (;;) {
DEFINE_WAIT(wait);
if (sk->sk_state != DECT_SK_LISTEN)
return -EINVAL;
if (!hlist_empty(&ssap->csk.accept_queue))
break;
if (!timeo)
return -EWOULDBLOCK;
if (signal_pending(tsk))
return sock_intr_errno(timeo);
prepare_to_wait_exclusive(&sk->sk_socket->wait, &wait,
TASK_INTERRUPTIBLE);
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
finish_wait(&sk->sk_socket->wait, &wait);
}
return 0;
}
static struct sock *dect_ssap_accept(struct sock *sk, int flags, int *errp)
{
struct dect_ssap *ssap = dect_ssap(sk);
struct sock *newsk;
int err;
lock_sock(sk);
err = dect_ssap_wait_req(sk, flags & O_NONBLOCK);
if (err < 0)
goto err;
newsk = dect_ssap_acceptq_dequeue(ssap);
release_sock(sk);
*errp = 0;
return newsk;
err:
release_sock(sk);
*errp = err;
return NULL;
}
static int dect_ssap_connect(struct sock *sk, struct sockaddr *uaddr, int len)
{
struct sockaddr_dect_ssap *addr = (struct sockaddr_dect_ssap *)uaddr;
struct dect_ssap *ssap = dect_ssap(sk);
struct dect_cluster *cl;
struct dect_dlei dlei;
struct dect_dli dli;
struct dect_lapc *lapc;
struct dect_lc *lc;
struct dect_mac_conn *mc;
bool new_mc = false, new_lc = false;
int err;
if (len < sizeof(*addr) || addr->dect_family != AF_DECT)
return -EINVAL;
err = dect_parse_dlei(&dlei, addr);
if (err < 0)
goto err1;
err = -ENODEV;
cl = dect_cluster_get_by_pari(&dlei.mci.ari);
if (cl == NULL)
goto err1;
/* The assignable class B LLNs may only be used for connections
* originating from a PT. The unassigned LLN may be used by an FT
* to request class B operation. Class A and U may be used by both.
*/
err = -EINVAL;
switch (dlei.lln) {
case DECT_LLN_ASSIGNABLE_MIN ... DECT_LLN_ASSIGNABLE_MAX:
if (cl->mode != DECT_MODE_PP)
goto err1;
break;
case DECT_LLN_UNASSIGNED:
if (cl->mode != DECT_MODE_FP)
goto err1;
break;
default:
break;
}
/* Lookup MAC connection and initiate new one if necessary */
err = -ENOMEM;
mc = dect_mac_conn_get_by_mci(cl, &dlei.mci);
if (mc == NULL) {
mc = dect_mac_conn_init(cl, &dlei.mci, NULL);
if (mc == NULL)
goto err1;
new_mc = true;
lc = NULL;
} else
lc = mc->lc;
/* Get Lc entity and verify LLN is available */
if (lc == NULL) {
lc = dect_lc_init(mc, GFP_KERNEL);
if (lc == NULL)
goto err2;
mc->lc = lc;
new_lc = true;
} else {
err = -EADDRINUSE;
if (lc->lapcs[dlei.lln] != NULL)
goto err2;
}
memcpy(&dli.mci, &dlei.mci, sizeof(dli.mci));
dli.lln = dlei.lln;
lapc = dect_lapc_init(&dli, dlei.sapi, lc, GFP_KERNEL);
if (lapc == NULL)
goto err3;
ssap->lapc = lapc;
sock_hold(sk);
lapc->sk = sk;
lc->lapcs[dlei.lln] = lapc;
if (new_mc)
err = dect_dlc_mac_conn_establish(mc);
else
dect_lapc_establish(lapc);
sk->sk_state = DECT_SK_ESTABLISH_PENDING;
return 0;
err3:
err2:
if (new_mc)
dect_dlc_mac_conn_release(mc);
err1:
return err;
}
static int dect_ssap_getname(struct sock *sk, struct sockaddr *uaddr, int *len,
int peer)
{
struct sockaddr_dect_ssap *addr = (struct sockaddr_dect_ssap *)uaddr;
struct dect_ssap *ssap = dect_ssap(sk);
#if 0
if (peer)
return -EOPNOTSUPP;
#endif
dect_build_dlei(addr, &ssap->dlei);
*len = sizeof(*addr);
return 0;
}
static int dect_ssap_recvmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, size_t len,
int noblock, int flags, int *addr_len)
{
struct sockaddr_dect *addr;
struct sk_buff *skb;
size_t copied = 0;
int err;
if (flags & MSG_OOB)
return -EOPNOTSUPP;
if (sk->sk_type == SOCK_SEQPACKET) {
lock_sock(sk);
if (sk->sk_state != DECT_SK_ESTABLISHED) {
release_sock(sk);
return -ENOTCONN;
}
release_sock(sk);
}
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (skb == NULL)
goto out;
copied = skb->len;
if (len < copied) {
msg->msg_flags |= MSG_TRUNC;
copied = len;
}
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (err < 0)
goto out_free;
if (msg->msg_name != NULL) {
addr = (struct sockaddr_dect *)msg->msg_name;
addr->dect_family = AF_DECT;
addr->dect_index = DECT_SK_CB(skb)->index;
msg->msg_namelen = sizeof(*addr);
}
sock_recv_timestamp(msg, sk, skb);
if (flags & MSG_TRUNC)
copied = skb->len;
out_free:
skb_free_datagram(sk, skb);
out:
return err ? : copied;
}
static int dect_ssap_sendmsg(struct kiocb *kiocb, struct sock *sk,
struct msghdr *msg, size_t len)
{
struct dect_ssap *ssap = dect_ssap(sk);
struct sk_buff *skb;
long timeo;
int err;
if (msg->msg_flags & MSG_OOB)
return -EOPNOTSUPP;
if (len > DECT_FA_I_MAX)
return -EMSGSIZE;
if (sk->sk_type == SOCK_SEQPACKET) {
lock_sock(sk);
if (sk->sk_state != DECT_SK_ESTABLISHED) {
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
err = sk_stream_wait_connect(sk, &timeo);
if (err < 0) {
release_sock(sk);
return err;
}
}
release_sock(sk);
}
skb = sock_alloc_send_skb(sk, len + 16, msg->msg_flags & MSG_DONTWAIT, &err);
if (skb == NULL)
goto err1;
skb_reset_mac_header(skb);
skb_reserve(skb, 16);
err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
if (err < 0)
goto err2;
skb_queue_tail(&sk->sk_write_queue, skb);
dect_lapc_transmit(ssap->lapc);
return len;
err2:
kfree_skb(skb);
err1:
return err;
}
static struct dect_proto dect_ssap_proto __read_mostly = {
.type = SOCK_SEQPACKET,
.protocol = DECT_S_SAP,
.capability = CAP_NET_RAW,
.ops = &dect_stream_ops,
.proto.name = "DECT_S_SAP",
.proto.owner = THIS_MODULE,
.proto.obj_size = sizeof(struct dect_ssap),
.proto.init = dect_ssap_init,
.proto.close = dect_ssap_close,
.proto.bind = dect_ssap_bind,
.proto.hash = dect_ssap_hash,
.proto.unhash = dect_ssap_unhash,
.proto.accept = dect_ssap_accept,
.proto.connect = dect_ssap_connect,
.proto.recvmsg = dect_ssap_recvmsg,
.proto.sendmsg = dect_ssap_sendmsg,
.getname = dect_ssap_getname,
};
int __init dect_ssap_module_init(void)
{
BUILD_BUG_ON(sizeof(struct sockaddr_dect_ssap) >
sizeof(struct sockaddr));
return dect_proto_register(&dect_ssap_proto);
}
void dect_ssap_module_exit(void)
{
dect_proto_unregister(&dect_ssap_proto);
}
MODULE_ALIAS_NET_PF_PROTO(PF_DECT, DECT_S_SAP);

79
net/dect/dlc_uplane.c Normal file
View File

@ -0,0 +1,79 @@
/*
* DECT DLC U-plane
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define DEBUG
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/net.h>
#include <linux/dect.h>
#include <net/dect/dect.h>
static struct sk_buff *dect_fbn_dequeue(struct dect_fbx *fbx)
{
struct dect_lux *lux = container_of(fbx, struct dect_lux, fbx);
return lux->ops->dequeue(lux);
}
static void dect_fbn_enqueue(struct dect_fbx *fbx, struct sk_buff *skb)
{
struct dect_lux *lux = container_of(fbx, struct dect_lux, fbx);
lux->ops->enqueue(lux, skb);
}
const struct dect_fbx_ops dect_fbn_ops = {
.dequeue = dect_fbn_dequeue,
.enqueue = dect_fbn_enqueue,
};
struct sk_buff *dect_uplane_dtr(struct dect_mac_conn *mc, enum dect_data_channels chan)
{
struct dect_fbx *fbx;
fbx = mc->fbx;
if (fbx == NULL)
return NULL;
return fbx->ops->dequeue(fbx);
}
void dect_uplane_rcv(struct dect_mac_conn *mc, enum dect_data_channels chan,
struct sk_buff *skb)
{
struct dect_fbx *fbx;
fbx = mc->fbx;
if (fbx == NULL)
return;
fbx->ops->enqueue(fbx, skb);
}
void dect_uplane_notify_state_change(struct dect_mac_conn *mc)
{
struct dect_lux *lux;
struct dect_fbx *fbx;
fbx = mc->fbx;
if (fbx == NULL)
return;
lux = container_of(fbx, struct dect_lux, fbx);
switch (mc->state) {
case DECT_MAC_CONN_OPEN_PENDING:
break;
case DECT_MAC_CONN_OPEN:
break;
case DECT_MAC_CONN_CLOSED:
return lux->ops->disconnect(lux);
}
}

212
net/dect/identities.c Normal file
View File

@ -0,0 +1,212 @@
/*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/dect.h>
#include <net/dect/dect.h>
bool dect_ari_masked_cmp(const struct dect_ari *a1, const struct dect_ari *a2,
const struct dect_ari *m)
{
/* An empty class mask implies a wildcard for everything */
if (!m->arc)
return false;
if (a1->arc != a2->arc)
return true;
if ((a1->fpn ^ a2->fpn) & m->fpn)
return true;
switch (a1->arc) {
case DECT_ARC_A:
return ((a1->emc ^ a2->emc) & m->emc);
case DECT_ARC_B:
return (((a1->eic ^ a2->eic) & m->eic) |
((a1->fps ^ a2->fps) & m->fps));
case DECT_ARC_C:
return (((a1->poc ^ a2->poc) & m->poc) |
((a1->fps ^ a2->fps) & m->fps));
case DECT_ARC_D:
return ((a1->gop ^ a2->gop) & m->gop);
case DECT_ARC_E:
return ((a1->fil ^ a2->fil) & m->fil);
default:
return true;
}
}
bool dect_ari_cmp(const struct dect_ari *a1, const struct dect_ari *a2)
{
static const struct dect_ari mask = {
.arc = ~0,
.fpn = ~0,
.fps = ~0,
{ ~0 }
};
return dect_ari_masked_cmp(a1, a2, &mask);
}
u8 dect_parse_ari(struct dect_ari *ari, u64 a)
{
ari->arc = (a & DECT_ARI_ARC_MASK) >> DECT_ARI_ARC_SHIFT;
switch (ari->arc) {
case DECT_ARC_A:
ari->emc = (a & DECT_ARI_A_EMC_MASK) >> DECT_ARI_A_EMC_SHIFT;
ari->fpn = (a & DECT_ARI_A_FPN_MASK) >> DECT_ARI_A_FPN_SHIFT;
return DECT_ARC_A_LEN;
case DECT_ARC_B:
ari->eic = (a & DECT_ARI_B_EIC_MASK) >> DECT_ARI_B_EIC_SHIFT;
ari->fpn = (a & DECT_ARI_B_FPN_MASK) >> DECT_ARI_B_FPN_SHIFT;
ari->fps = (a & DECT_ARI_B_FPS_MASK) >> DECT_ARI_B_FPS_SHIFT;
return DECT_ARC_B_LEN;
case DECT_ARC_C:
ari->poc = (a & DECT_ARI_C_POC_MASK) >> DECT_ARI_C_POC_SHIFT;
ari->fpn = (a & DECT_ARI_C_FPN_MASK) >> DECT_ARI_C_FPN_SHIFT;
ari->fps = (a & DECT_ARI_C_FPS_MASK) >> DECT_ARI_C_FPS_SHIFT;
return DECT_ARC_C_LEN;
case DECT_ARC_D:
ari->gop = (a & DECT_ARI_D_GOP_MASK) >> DECT_ARI_D_GOP_SHIFT;
ari->fpn = (a & DECT_ARI_D_FPN_MASK) >> DECT_ARI_D_FPN_SHIFT;
return DECT_ARC_D_LEN;
case DECT_ARC_E:
ari->fil = (a & DECT_ARI_E_FIL_MASK) >> DECT_ARI_E_FIL_SHIFT;
ari->fpn = (a & DECT_ARI_E_FPN_MASK) >> DECT_ARI_E_FPN_SHIFT;
return DECT_ARC_E_LEN;
default:
return 0;
}
}
EXPORT_SYMBOL_GPL(dect_parse_ari);
u64 dect_build_ari(const struct dect_ari *ari)
{
u64 a = 0;
a |= (u64)ari->arc << DECT_ARI_ARC_SHIFT;
switch (ari->arc) {
case DECT_ARC_A:
a |= (u64)ari->emc << DECT_ARI_A_EMC_SHIFT;
a |= (u64)ari->fpn << DECT_ARI_A_FPN_SHIFT;
break;
case DECT_ARC_B:
a |= (u64)ari->eic << DECT_ARI_B_EIC_SHIFT;
a |= (u64)ari->fpn << DECT_ARI_B_FPN_SHIFT;
a |= (u64)ari->fps << DECT_ARI_B_FPS_SHIFT;
break;
case DECT_ARC_C:
a |= (u64)ari->poc << DECT_ARI_C_POC_SHIFT;
a |= (u64)ari->fpn << DECT_ARI_C_FPN_SHIFT;
a |= (u64)ari->fps << DECT_ARI_C_FPS_SHIFT;
break;
case DECT_ARC_D:
a |= (u64)ari->gop << DECT_ARI_D_GOP_SHIFT;
a |= (u64)ari->fpn << DECT_ARI_D_FPN_SHIFT;
break;
case DECT_ARC_E:
a |= (u64)ari->fil << DECT_ARI_E_FIL_SHIFT;
a |= (u64)ari->fpn << DECT_ARI_E_FPN_SHIFT;
break;
}
return a;
}
u64 dect_build_rfpi(const struct dect_idi *idi)
{
u64 t = 0;
t |= idi->e ? DECT_RFPI_E_FLAG : 0;
t |= dect_build_ari(&idi->pari) >> DECT_RFPI_ARI_SHIFT;
t |= idi->rpn << DECT_RFPI_RPN_SHIFT;
return t;
}
bool dect_rfpi_cmp(const struct dect_idi *i1, const struct dect_idi *i2)
{
return dect_ari_cmp(&i1->pari, &i2->pari) ||
i1->rpn != i2->rpn ||
i1->e != i2->e;
}
u16 dect_build_fmid(const struct dect_idi *idi)
{
u64 rfpi;
rfpi = dect_build_rfpi(idi);
rfpi >>= (sizeof(rfpi) - DECT_NT_ID_RFPI_LEN) * BITS_PER_BYTE;
return rfpi & DECT_FMID_MASK;
}
/*
* PMID (Portable MAC Identity)
*/
void dect_parse_pmid(struct dect_pmid *pmid, u32 p)
{
if ((p & DECT_PMID_DEFAULT_ID_MASK) == DECT_PMID_DEFAULT_ID) {
pmid->type = DECT_PMID_DEFAULT;
pmid->num = p & DECT_PMID_DEFAULT_NUM_MASK;
} else if ((p & DECT_PMID_EMERGENCY_ID_MASK) == DECT_PMID_EMERGENCY_ID) {
pmid->type = DECT_PMID_EMERGENCY;
pmid->tpui = p & DECT_PMID_EMERGENCY_TPUI_MASK;
} else {
pmid->type = DECT_PMID_ASSIGNED;
pmid->tpui = p & DECT_PMID_ASSIGNED_TPUI_MASK;
}
}
u32 dect_build_pmid(const struct dect_pmid *pmid)
{
u32 p = 0;
switch (pmid->type) {
case DECT_PMID_DEFAULT:
p |= DECT_PMID_DEFAULT_ID;
p |= pmid->tpui;
break;
case DECT_PMID_EMERGENCY:
p |= DECT_PMID_EMERGENCY_ID;
p |= pmid->tpui;
break;
case DECT_PMID_ASSIGNED:
p |= pmid->tpui;
break;
}
return p;
}
bool dect_pmid_cmp(const struct dect_pmid *p1, const struct dect_pmid *p2)
{
return memcmp(p1, p2, sizeof(*p1));
}
/**
* dect_parse_mci - Extract the MCI elements from a packed MCI in a
* struct sockaddr_dect_lu
*
* The packed MCI is build from ARI + PMID + LCN
*/
int dect_parse_mci(struct dect_mci *mci, u64 m)
{
u32 p;
u8 len;
len = dect_parse_ari(&mci->ari, m);
len += DECT_PMID_SIZE;
p = (m >> (sizeof(m) * BITS_PER_BYTE - len)) & DECT_PMID_MASK;
dect_parse_pmid(&mci->pmid, p);
len += DECT_ECN_SIZE;
mci->lcn = (m >> (sizeof(m) * BITS_PER_BYTE - len)) & DECT_LCN_MASK;
return 0;
}
u64 dect_build_mci(const struct dect_mci *mci)
{
return 0;
}

482
net/dect/mac_ccf.c Normal file
View File

@ -0,0 +1,482 @@
/*
* DECT MAC Cluster Control Functions
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define DEBUG
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/net.h>
#include <linux/dect.h>
#include <net/dect/dect.h>
#include <net/dect/mac_ccf.h>
#include <net/dect/mac_csf.h>
#include <net/dect/ccp.h>
static struct dect_cell_handle *
dect_cluster_get_cell_by_rpn(struct dect_cluster *cl, u8 rpn)
{
struct dect_cell_handle *ch;
list_for_each_entry(ch, &cl->cells, list) {
if (ch->rpn == rpn)
return ch;
}
return NULL;
}
static void dect_scan_report(const struct dect_cluster_handle *clh,
const struct dect_scan_result *res)
{
struct dect_cluster *cl = container_of(clh, struct dect_cluster, handle);
dect_llme_scan_result_notify(cl, res);
}
static void dect_mac_info_indicate(const struct dect_cluster_handle *clh,
const struct dect_idi *idi,
const struct dect_si *si)
{
struct dect_cluster *cl = container_of(clh, struct dect_cluster, handle);
printk("cl %p: mac info indicate\n", cl);
memcpy(&cl->si, si, sizeof(cl->si));
}
/*
* Broadcast message control
*/
/**
* dect_bmc_mac_page_request - queue one segment of B_S channel data
*
* @cl: DECT cluster
* @skb: SDU
* @expedited: fast/normal page indication
*/
void dect_bmc_mac_page_request(struct dect_cluster *cl, struct sk_buff *skb,
bool expedited)
{
const struct dect_cell_handle *ch, *last = NULL;
struct sk_buff *clone;
BUG_ON(cl->mode != DECT_MODE_FP);
DECT_BMC_CB(skb)->fast = expedited;
list_for_each_entry(ch, &cl->cells, list) {
if (last != NULL) {
clone = skb_clone(skb, GFP_ATOMIC);
if (clone != NULL)
ch->ops->page_request(ch, clone);
}
last = ch;
}
if (last != NULL)
last->ops->page_request(last, skb);
}
static void dect_bmc_page_indicate(const struct dect_cluster_handle *clh,
struct sk_buff *skb)
{
struct dect_cluster *cl = container_of(clh, struct dect_cluster, handle);
return dect_dlc_mac_page_indicate(cl, skb);
}
/*
* Multi-Bearer Control
*/
#define mbc_debug(mbc, fmt, args...) \
pr_debug("MBC (MCEI %u): " fmt, (mbc)->id.mcei, ## args);
static struct dect_mbc *dect_mbc_get_by_mcei(struct dect_cluster *cl, u32 mcei)
{
struct dect_mbc *mbc;
list_for_each_entry(mbc, &cl->mbcs, list) {
if (mbc->id.mcei == mcei)
return mbc;
}
return NULL;
}
u32 dect_mbc_alloc_mcei(struct dect_cluster *cl)
{
u32 mcei;
while (1) {
mcei = ++cl->mcei_rover;
if (mcei == 0)
continue;
if (dect_mbc_get_by_mcei(cl, mcei))
continue;
return mcei;
}
}
static void dect_mbc_timeout(unsigned long data)
{
struct dect_mbc *mbc = (struct dect_mbc *)data;
mbc_debug(mbc, "timeout");
}
static void dect_mbc_release(struct dect_mbc *mbc)
{
del_timer_sync(&mbc->timer);
list_del(&mbc->list);
#if 0
if (ch != NULL)
ch->ops->tbc_release(ch, &mbc->id);
#endif
kfree(mbc);
}
static struct dect_mbc *dect_mbc_init(struct dect_cluster *cl,
const struct dect_mbc_id *id)
{
struct dect_mbc *mbc;
mbc = kzalloc(sizeof(*mbc), GFP_ATOMIC);
if (mbc == NULL)
return NULL;
memcpy(&mbc->id, id, sizeof(mbc->id));
mbc->state = DECT_MBC_NONE;
setup_timer(&mbc->timer, dect_mbc_timeout, (unsigned long)mbc);
skb_queue_head_init(&mbc->c_tx_queue);
skb_queue_head_init(&mbc->i_tx_queue);
skb_queue_head_init(&mbc->gf_tx_queue);
mbc->cs_rx_seq = 1;
mbc->cs_tx_seq = 1;
list_add_tail(&mbc->list, &cl->mbcs);
return mbc;
}
static int dect_mbc_setup_tbc(struct dect_mbc *mbc)
{
const struct dect_cell_handle *ch = mbc->ch;
struct dect_channel_desc chd;
int err;
memset(&chd, 0, sizeof(chd));
chd.pkt = DECT_PACKET_P32;
chd.b_fmt = DECT_B_UNPROTECTED;
err = ch->ops->tbc_initiate(ch, &mbc->id, &chd);
if (err < 0)
return err;
mbc->setup_cnt++;
return 0;
}
/**
* dect_mbc_con_request - request a new MAC connection
*
* @cl: DECT cluster
* @id: MBC identifier
*/
int dect_mbc_con_request(struct dect_cluster *cl, const struct dect_mbc_id *id)
{
struct dect_cell_handle *ch;
struct dect_mbc *mbc;
int err;
err = -EHOSTUNREACH;
ch = dect_cluster_get_cell_by_rpn(cl, 0);
if (ch == NULL)
goto err1;
err = -ENOMEM;
mbc = dect_mbc_init(cl, id);
if (mbc == NULL)
goto err1;
mbc->state = DECT_MBC_INITIATED;
mbc->ch = ch;
err = dect_mbc_setup_tbc(mbc);
if (err < 0)
goto err2;
mod_timer(&mbc->timer, jiffies + DECT_MBC_SETUP_TIMEOUT);
return 0;
err2:
dect_mbc_release(mbc);
err1:
return err;
}
static int dect_mbc_conn_indicate(const struct dect_cluster_handle *clh,
const struct dect_cell_handle *ch,
const struct dect_mbc_id *id)
{
struct dect_cluster *cl = container_of(clh, struct dect_cluster, handle);
struct dect_mbc_id mid;
struct dect_mbc *mbc;
int err;
memcpy(&mid, id, sizeof(mid));
mid.mcei = dect_mbc_alloc_mcei(cl);
err = -ENOMEM;
mbc = dect_mbc_init(cl, &mid);
if (mbc == NULL)
goto err1;
mbc->ch = ch;
err = ch->ops->tbc_confirm(ch, &mid);
if (err < 0)
goto err2;
mod_timer(&mbc->timer, jiffies + DECT_MBC_SETUP_TIMEOUT);
return 0;
err2:
dect_mbc_release(mbc);
err1:
return err;
}
static int dect_mbc_conn_notify(const struct dect_cluster_handle *clh,
const struct dect_mbc_id *id,
enum dect_tbc_event event)
{
struct dect_cluster *cl = container_of(clh, struct dect_cluster, handle);
struct dect_mbc *mbc;
mbc = dect_mbc_get_by_mcei(cl, id->mcei);
if (mbc == NULL)
return -ENOENT;
mbc_debug(mbc, "notify event: %u\n", event);
switch (event) {
case DECT_TBC_SETUP_FAILED:
switch (mbc->state) {
case DECT_MBC_NONE:
return 0;
case DECT_MBC_INITIATED:
if (++mbc->setup_cnt > DECT_MBC_SETUP_MAX_ATTEMPTS ||
dect_mbc_setup_tbc(mbc) < 0)
return dect_dlc_mac_conn_disconnect(cl, id->mcei);
return 0;
default:
return WARN_ON(-1);
}
case DECT_TBC_SETUP_COMPLETE:
switch (mbc->state) {
case DECT_MBC_NONE:
return dect_dlc_mac_conn_indicate(cl, id);
case DECT_MBC_INITIATED:
return dect_dlc_mac_conn_confirm(cl, id->mcei, id->service);
default:
return WARN_ON(-1);
}
case DECT_TBC_HANDSHAKE_TIMEOUT:
case DECT_TBC_REMOTE_RELEASE:
return dect_dlc_mac_conn_disconnect(cl, id->mcei);
default:
return WARN_ON(-1);
}
}
int dect_mbc_co_data_request(struct dect_cluster *cl, u32 mcei,
enum dect_mac_channels chan,
struct sk_buff *skb)
{
struct dect_mbc *mbc;
mbc = dect_mbc_get_by_mcei(cl, mcei);
if (mbc == NULL) {
kfree_skb(skb);
return -ENOTCONN;
}
switch (chan) {
case DECT_MC_C_S:
skb_queue_tail(&mbc->c_tx_queue, skb);
break;
case DECT_MC_I_N:
skb_queue_tail(&mbc->i_tx_queue, skb);
break;
case DECT_MC_G_F:
skb_queue_tail(&mbc->gf_tx_queue, skb);
break;
default:
BUG();
}
return 0;
}
static void dect_mbc_data_indicate(const struct dect_cluster_handle *clh,
const struct dect_mbc_id *id,
enum dect_data_channels chan,
struct sk_buff *skb)
{
struct dect_cluster *cl = container_of(clh, struct dect_cluster, handle);
struct dect_mbc *mbc;
mbc = dect_mbc_get_by_mcei(cl, id->mcei);
if (mbc == NULL)
goto err;
return dect_dlc_mac_co_data_indicate(cl, mbc->id.mcei, chan, skb);
err:
kfree_skb(skb);
}
static void dect_mbc_dtr_indicate(const struct dect_cluster_handle *clh,
const struct dect_mbc_id *id,
enum dect_data_channels chan)
{
struct dect_cluster *cl = container_of(clh, struct dect_cluster, handle);
struct dect_mbc *mbc;
struct sk_buff *skb;
mbc = dect_mbc_get_by_mcei(cl, id->mcei);
if (mbc == NULL)
return;
mbc_debug(mbc, "DTR-indicate\n");
skb = dect_dlc_mac_co_dtr_indicate(cl, mbc->id.mcei, chan);
if (skb == NULL)
return;
mbc->ch->ops->tbc_data_request(mbc->ch, &mbc->id, chan, skb);
mbc->cs_tx_seq++;
}
static void dect_cluster_unbind_cell(struct dect_cluster_handle *clh,
struct dect_cell_handle *ch)
{
list_del(&ch->list);
}
static int dect_cluster_enable_cell(struct dect_cluster *cl,
struct dect_cell_handle *ch)
{
int err;
err = ch->ops->preload(ch, &cl->pari, ch->rpn, &cl->si);
if (err < 0)
return err;
err = ch->ops->enable(ch);
if (err < 0)
return err;
return 0;
}
static int dect_cluster_bind_cell(struct dect_cluster_handle *clh,
struct dect_cell_handle *ch)
{
struct dect_cluster *cl = container_of(clh, struct dect_cluster, handle);
u8 rpn, max;
int err;
/* Allocate RPN for the cell */
max = 8;
for (rpn = 0; rpn < max; rpn++) {
if (!dect_cluster_get_cell_by_rpn(cl, rpn))
break;
}
if (rpn == max)
return -EMFILE;
ch->clh = clh;
ch->rpn = rpn;
err = ch->ops->set_mode(ch, cl->mode);
if (err < 0)
return err;
err = dect_cluster_enable_cell(cl, ch);
if (err < 0)
return err;
list_add_tail(&ch->list, &cl->cells);
return 0;
}
static const struct dect_ccf_ops dect_ccf_ops = {
.bind = dect_cluster_bind_cell,
.unbind = dect_cluster_unbind_cell,
.scan_report = dect_scan_report,
.mac_info_indicate = dect_mac_info_indicate,
.mbc_conn_indicate = dect_mbc_conn_indicate,
.mbc_conn_notify = dect_mbc_conn_notify,
.mbc_data_indicate = dect_mbc_data_indicate,
.mbc_dtr_indicate = dect_mbc_dtr_indicate,
.bmc_page_indicate = dect_bmc_page_indicate,
};
int dect_cluster_scan(struct dect_cluster *cl,
const struct dect_llme_req *lreq,
const struct dect_ari *pari,
const struct dect_ari *pari_mask)
{
struct dect_cell_handle *ch;
ch = dect_cluster_get_cell_by_rpn(cl, 0);
if (ch == NULL)
return -ENOENT;
return ch->ops->scan(ch, lreq, pari, pari_mask);
}
static void dect_fp_init_si(struct dect_cluster *cl)
{
struct dect_si *si = &cl->si;
/* Make phone not go into "call technician" mode :) */
si->ssi.rfcars = 0x3ff;
si->fpc.fpc = DECT_FPC_FULL_SLOT |
DECT_FPC_CO_SETUP_ON_DUMMY |
DECT_FPC_CL_UPLINK |
DECT_FPC_CL_DOWNLINK |
DECT_FPC_BASIC_A_FIELD_SETUP |
DECT_FPC_CF_MESSAGES |
DECT_FPC_IN_MIN_DELAY |
DECT_FPC_IN_NORM_DELAY |
DECT_FPC_IP_ERROR_DETECTION |
DECT_FPC_IP_ERROR_CORRECTION;
si->fpc.hlc = DECT_HLC_ADPCM_G721_VOICE |
DECT_HLC_GAP_PAP_BASIC_SPEECH |
DECT_HLC_CISS_SERVICE |
DECT_HLC_CLMS_SERVICE |
DECT_HLC_COMS_SERVICE;
}
void dect_cluster_init(struct dect_cluster *cl)
{
spin_lock_init(&cl->lock);
INIT_LIST_HEAD(&cl->bmc.bcs);
INIT_LIST_HEAD(&cl->mbcs);
INIT_LIST_HEAD(&cl->cells);
INIT_LIST_HEAD(&cl->mac_connections);
if (cl->mode == DECT_MODE_FP)
dect_fp_init_si(cl);
cl->handle.ops = &dect_ccf_ops;
cl->handle.index = cl->index;
// FIXME:
if (dect_ccp_cluster_init(cl) < 0)
printk("CCP init failed\n");
}
void dect_cluster_shutdown(struct dect_cluster *cl)
{
struct dect_cell_handle *ch, *next;
list_for_each_entry_safe(ch, next, &cl->cells, list)
dect_cluster_unbind_cell(&cl->handle, ch);
dect_ccp_cluster_shutdown(cl);
}

3574
net/dect/mac_csf.c Normal file

File diff suppressed because it is too large Load Diff

212
net/dect/raw.c Normal file
View File

@ -0,0 +1,212 @@
/*
* DECT RAW sockets
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/dect.h>
#include <net/sock.h>
#include <net/dect/dect.h>
#include <net/dect/mac_csf.h>
static HLIST_HEAD(dect_raw_sockets);
struct dect_raw_sk {
struct sock sk;
};
static inline struct dect_raw_sk *dect_raw_sk(struct sock *sk)
{
return (struct dect_raw_sk *)sk;
}
static void __dect_raw_rcv(struct sk_buff *skb)
{
struct dect_cell *cell = DECT_TRX_CB(skb)->trx->cell;
struct hlist_node *node;
struct sk_buff *skb2;
struct sock *sk;
sk_for_each_bound(sk, node, &dect_raw_sockets) {
if (sk->sk_bound_dev_if &&
sk->sk_bound_dev_if != cell->index)
continue;
skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2 == NULL) {
sk->sk_err = -ENOMEM;
sk->sk_error_report(sk);
} else {
/* Release the transceiver reference, it is only valid
* in IRQ and softirq context.
*/
DECT_TRX_CB(skb)->trx = NULL;
if (dect_sock_queue_rcv_skb(sk, skb2) < 0)
kfree_skb(skb2);
}
}
}
static int dect_raw_release(struct socket *sock)
{
struct sock *sk = sock->sk;
if (!hlist_unhashed(&sk->sk_bind_node))
__sk_del_bind_node(sk);
sock_put(sk);
return 0;
}
static int dect_raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
{
struct sockaddr_dect *addr = (struct sockaddr_dect *)uaddr;
struct sock *sk = sock->sk;
if (len < sizeof(*addr) || addr->dect_family != AF_DECT)
return -EINVAL;
if (addr->dect_index != 0 &&
!dect_cell_get_by_index(addr->dect_index))
return -ENODEV;
lock_sock(sk);
sk->sk_bound_dev_if = addr->dect_index;
if (!hlist_unhashed(&sk->sk_bind_node))
__sk_del_bind_node(sk);
sk_add_bind_node(sk, &dect_raw_sockets);
release_sock(sk);
return 0;
}
static int dect_raw_getname(struct socket *sock, struct sockaddr *uaddr,
int *len, int peer)
{
struct sockaddr_dect *addr = (struct sockaddr_dect *)uaddr;
struct sock *sk = sock->sk;
if (peer)
return -EOPNOTSUPP;
addr->dect_family = AF_DECT;
addr->dect_index = sk->sk_bound_dev_if;
*len = sizeof(*addr);
return 0;
}
static int dect_raw_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t len, int flags)
{
struct sockaddr_dect *addr;
struct dect_raw_auxdata aux;
struct sock *sk = sock->sk;
struct sk_buff *skb;
int noblock = flags & MSG_DONTWAIT;
size_t copied = 0;
int err;
if (flags & MSG_OOB)
return -EOPNOTSUPP;
noblock = flags & MSG_DONTWAIT;
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (skb == NULL)
goto out;
copied = skb->len;
if (len < copied) {
msg->msg_flags |= MSG_TRUNC;
copied = len;
}
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (err < 0)
goto out_free;
if (msg->msg_name != NULL) {
addr = (struct sockaddr_dect *)msg->msg_name;
addr->dect_family = AF_DECT;
addr->dect_index = DECT_SK_CB(skb)->index;
msg->msg_namelen = sizeof(*addr);
}
sock_recv_timestamp(msg, sk, skb);
aux.mfn = DECT_TRX_CB(skb)->mfn;
aux.frame = DECT_TRX_CB(skb)->frame;
aux.slot = DECT_TRX_CB(skb)->slot;
aux.rssi = DECT_TRX_CB(skb)->rssi;
put_cmsg(msg, SOL_DECT, DECT_RAW_AUXDATA, sizeof(aux), &aux);
if (flags & MSG_TRUNC)
copied = skb->len;
out_free:
skb_free_datagram(sk, skb);
out:
return err ? : copied;
}
static const struct proto_ops dect_raw_ops = {
.family = PF_DECT,
.owner = THIS_MODULE,
.release = dect_raw_release,
.bind = dect_raw_bind,
.connect = sock_no_connect,
.socketpair = sock_no_socketpair,
.getname = dect_raw_getname,
.poll = datagram_poll,
.ioctl = sock_no_ioctl,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = sock_no_setsockopt,
.getsockopt = sock_no_getsockopt,
.sendmsg = sock_no_sendmsg,
.recvmsg = dect_raw_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
};
static struct dect_proto dect_raw_proto = {
.type = SOCK_RAW,
.protocol = DECT_RAW,
.capability = CAP_NET_RAW,
.ops = &dect_raw_ops,
.proto.name = "DECT_RAW",
.proto.owner = THIS_MODULE,
.proto.obj_size = sizeof(struct dect_raw_sk),
};
static int __init dect_raw_init(void)
{
int err;
err = dect_proto_register(&dect_raw_proto);
if (err < 0)
return err;
rcu_assign_pointer(dect_raw_rcv_hook, __dect_raw_rcv);
return 0;
}
static void __exit dect_raw_exit(void)
{
rcu_assign_pointer(dect_raw_rcv_hook, NULL);
synchronize_rcu();
dect_proto_unregister(&dect_raw_proto);
}
module_init(dect_raw_init);
module_exit(dect_raw_exit);
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_DESCRIPTION("DECT RAW sockets");
MODULE_LICENSE("GPL");
MODULE_ALIAS_NET_PF_PROTO(PF_DECT, DECT_RAW);

724
net/dect/transceiver.c Normal file
View File

@ -0,0 +1,724 @@
/*
* DECT transceiver and transceiver group functions
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
//#define DEBUG
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/notifier.h>
#include <net/dect/dect.h>
#include <net/dect/mac_csf.h>
#include <net/dect/transceiver.h>
static RAW_NOTIFIER_HEAD(dect_transceiver_chain);
LIST_HEAD(dect_transceiver_list);
#define trx_debug(trx, fmt, args...) \
pr_debug("%s: " fmt, trx->name, ## args)
static const struct dect_band *dect_band[DECT_BAND_NUM];
static const u8 dect_pkt_size[] = {
[DECT_PACKET_P00] = DECT_P00_SIZE,
[DECT_PACKET_P08] = DECT_P08_SIZE,
[DECT_PACKET_P32] = DECT_P32_SIZE,
[DECT_PACKET_P80] = DECT_P80_SIZE,
};
/**
* dect_transceiver_alloc_skb - allocate a transceiver RX skb
*
* @trx: transceiver
* @slot: slot number
*
* Allocate a skb according to the receiving channel characteristics.
*/
struct sk_buff *dect_transceiver_alloc_skb(struct dect_transceiver *trx, u8 slot)
{
const struct dect_transceiver_slot *ts = &trx->slots[slot];
struct sk_buff *skb;
skb = alloc_skb(dect_pkt_size[ts->chd.pkt], GFP_ATOMIC);
if (skb == NULL)
return NULL;
DECT_TRX_CB(skb)->trx = trx;
DECT_TRX_CB(skb)->slot = ts->chd.slot;
/* Reserve room for preamble and set up adjacent packet data pointer */
skb_reserve(skb, DECT_PREAMBLE_SIZE);
skb_put(skb, dect_pkt_size[ts->chd.pkt] - DECT_PREAMBLE_SIZE);
return skb;
}
EXPORT_SYMBOL_GPL(dect_transceiver_alloc_skb);
/* Transceiver virtual clock maintenance:
*
* The transceiver layer processes the received frames from some slots in
* the past while the transceiver is transceiving on the following slots.
* Additionally the transceiver needs to be maintained for the upcoming
* slots. Therefore there are three different reference frames of time:
*
* [ RX ][ TRX ][ TX ]
* slot_0 -> slot_23
*
* - Real time, which is only known to the transceiver
*
* - RX time, which is a virtual clock following real time by at least one
* slot and advancing as received slots are processed. A transceiver must
* generate enough events so that the RX time never lags behind the TRX
* time for more than one TDMA half frame.
*
* - TX time, which is a virtual clock leading RX time by a usually constant
* amount of slots large enough so that packets queued to the transceiver
* will reach the transceiver in time to be sent. It always leads real time,
* but must never have a distance greater than one TDMA half frame from RX
* time, resulting in a maximal distance of 11 to real time.
*
* Transceivers periodically notify the transceiver layer of an elapsed amount
* of time and the frames that were received during that period. The events
* batches generated by multiple transceivers contained in a group are merged
* and processed as a single chronological event stream.
*
* The following steps are performed during processing (for every slot):
*
* - Received packets are passed to the MAC layer
* - A RX tick is generated, ending the last RX slot
* - A TX tick with some offset in the future is generated, beginning the
* next TX slot
*
* The RX and TX ticks are used by the MAC layer to maintain two timer bases
* for performing maintenance operations after a slot was received or before
* a slot will be transmitted.
*/
/**
* dect_transceiver_queue_event - queue a transceiver event for BH processing
*
* @trx: DECT transceiver
* @event: Transceiver event
*/
void dect_transceiver_queue_event(struct dect_transceiver *trx,
struct dect_transceiver_event *event)
{
struct dect_transceiver_group *grp = &trx->cell->trg;
spin_lock(&grp->lock);
list_add_tail(&event->list, &grp->events);
spin_unlock(&grp->lock);
tasklet_hi_schedule(&grp->tasklet);
}
EXPORT_SYMBOL_GPL(dect_transceiver_queue_event);
static struct dect_transceiver_event *
dect_dequeue_event(struct dect_transceiver_group *grp)
{
struct dect_transceiver_event *event;
unsigned long flags;
event = NULL;
spin_lock_irqsave(&grp->lock, flags);
if (!list_empty(&grp->events)) {
event = list_first_entry(&grp->events,
struct dect_transceiver_event,
list);
list_del(&event->list);
}
spin_unlock_irqrestore(&grp->lock, flags);
return event;
}
static void dect_tg_merge_events(struct dect_transceiver_group *grp,
struct dect_transceiver *trx,
struct dect_transceiver_event *event)
{
struct sk_buff *skb;
u8 slot, idx, i;
/* Transfer the packets to the slot input queues and mark the
* slot events.
*/
trx_debug(trx, "merge %u events pos %u rssi_mask %x\n",
trx->ops->eventrate, event->slotpos, event->rssi_mask);
for (i = 0; i < trx->ops->eventrate; i++) {
slot = event->slotpos + i;
idx = slot % ARRAY_SIZE(grp->slots);
skb = skb_peek(&event->rx_queue);
if (skb != NULL && DECT_TRX_CB(skb)->slot == slot) {
__skb_unlink(skb, &event->rx_queue);
__skb_queue_tail(&grp->slots[idx].queue, skb);
} else if (event->rssi_mask & (1 << i))
grp->slots[idx].rssi[trx->index] = event->rssi[i];
grp->slots[idx].mask |= 1 << trx->index;
}
}
static bool seqno_before(u32 seq1, u32 seq2)
{
return (s32)(seq2 - seq1) > 0;
}
static bool seqno_after(u32 seq1, u32 seq2)
{
return seqno_before(seq2, seq1);
}
static void dect_tg_process_events(struct dect_transceiver_group *grp)
{
struct dect_transceiver *trx;
struct dect_transceiver_slot *ts;
struct sk_buff *skb;
u8 idx, d, i;
u16 late;
pr_debug("process events slot_low=%u slot_high=%u distance=%u\n",
grp->slot_low, grp->slot_high,
dect_slot_distance(grp->slot_low, grp->slot_high));
while (grp->slot_low != grp->slot_high) {
/*
* If more than one half frame is missing, only forward the
* clock since the slot positions refer to slots in the
* following half frame.
*/
d = dect_slot_distance(grp->slot_low, grp->slot_high);
if (d > ARRAY_SIZE(grp->slots))
goto tick;
idx = grp->slot_low % ARRAY_SIZE(grp->slots);
/* Check for transceivers which are lagging by more than their
* event rate window and mark the current window entirely as
* lost.
*/
late = grp->slots[idx].mask ^ grp->trxmask;
while (late != 0) {
trx = grp->trx[ffs(late) - 1];
late &= ~(1 << trx->index);
if (!seqno_before(trx->seqno + trx->ops->eventrate,
grp->seqno) &&
d <= trx->ops->eventrate)
continue;
trx_debug(trx, "late for window %u\n", grp->slot_low);
for (i = 0; i < trx->ops->eventrate; i++)
grp->slots[(idx + i) % 12].mask |= 1 << trx->index;
trx->stats.event_late++;
}
if (grp->slots[idx].mask != grp->trxmask) {
pr_debug("slot %u incomplete: mask %x trx %x\n",
grp->slot_low, grp->slots[idx].mask, grp->trxmask);
break;
}
while ((skb = __skb_dequeue(&grp->slots[idx].queue))) {
trx = DECT_TRX_CB(skb)->trx;
ts = &trx->slots[DECT_TRX_CB(skb)->slot];
dect_mac_rcv(trx, ts, skb);
}
for (i = 0; i < ARRAY_SIZE(grp->slots[idx].rssi); i++) {
if (grp->slots[idx].rssi[i] == 0)
continue;
trx = grp->trx[i];
ts = &trx->slots[grp->slot_low];
dect_mac_report_rssi(trx, ts, grp->slots[idx].rssi[i]);
grp->slots[idx].rssi[i] = 0;
}
grp->slots[idx].mask = 0;
tick:
dect_mac_rx_tick(grp, dect_next_slotnum(grp->slot_low));
dect_mac_tx_tick(grp, dect_slot_add(grp->slot_low,
2 * grp->latency));
grp->slot_low = dect_next_slotnum(grp->slot_low);
}
}
/*
* Softirq transceiver group event processing
*/
static void dect_transceiver_tasklet(unsigned long data)
{
struct dect_transceiver_group *grp = (struct dect_transceiver_group *)data;
struct dect_transceiver *trx;
struct dect_transceiver_event *event;
struct sk_buff *skb;
again:
event = dect_dequeue_event(grp);
if (event == NULL)
return;
trx = event->trx;
trx_debug(trx, "event handler: trx: seq %u pos %u grp: seq %u pos %u\n",
trx->seqno, event->slotpos, grp->seqno, grp->slot_low);
/* Before a transceiver is locked, its timing might vary and isn't
* synchronized to the remaining group. The MAC layer handles this
* manually.
*/
if (trx->state != DECT_TRANSCEIVER_LOCKED) {
skb = __skb_dequeue(&event->rx_queue);
if (skb != NULL)
dect_mac_irc_rcv(trx, skb);
dect_mac_irc_tick(trx);
goto out;
}
/* If a secondary transceiver enters locked state or a tranceiver missed
* a previous window, its sequence number is out of sync. Resync it once
* it starts reporting events in the current window.
*
* FIXME: driver should ignore frames with missed interrupts completely
* FIXME2: off by one window if receiver is not first
*/
if (seqno_before(trx->seqno + trx->ops->eventrate, grp->seqno)) {
if (event->slotpos != grp->slot_low) {
trx_debug(trx, "unsynchronized\n");
__skb_queue_purge(&event->rx_queue);
goto out;
}
trx->seqno = grp->seqno;
trx_debug(trx, "synchronized to seqno %u\n", trx->seqno);
}
/* Merge the events and update the sequence number. The transceiver
* with the highest sequence number determines the slot position for
* the entire group.
*/
dect_tg_merge_events(grp, trx, event);
trx->seqno += trx->ops->eventrate;
if (seqno_after(trx->seqno, grp->seqno)) {
grp->seqno = trx->seqno;
grp->slot_high =
dect_slot_add(event->slotpos, trx->ops->eventrate);
}
dect_tg_process_events(grp);
out:
dect_release_transceiver_event(event);
goto again;
}
int dect_transceiver_group_add(struct dect_transceiver_group *grp,
struct dect_transceiver *trx)
{
u8 index;
index = ffz(grp->trxmask);
if (index >= ARRAY_SIZE(grp->trx))
return -EMFILE;
trx->index = index;
grp->trx[index] = trx;
if (trx->ops->latency > grp->latency)
grp->latency = trx->ops->latency;
grp->trxmask |= 1 << index;
return 0;
}
void dect_transceiver_group_remove(struct dect_transceiver_group *grp,
struct dect_transceiver *trx)
{
grp->trxmask &= ~(1 << trx->index);
/* Synchronize with interrupt and softirq processing */
synchronize_rcu();
grp->trx[trx->index] = NULL;
}
void dect_transceiver_group_init(struct dect_transceiver_group *grp)
{
unsigned int i;
spin_lock_init(&grp->lock);
INIT_LIST_HEAD(&grp->events);
for (i = 0; i < ARRAY_SIZE(grp->slots); i++)
__skb_queue_head_init(&grp->slots[i].queue);
tasklet_init(&grp->tasklet, dect_transceiver_tasklet,
(unsigned long)grp);
}
void dect_transceiver_disable(struct dect_transceiver *trx)
{
trx->ops->disable(trx);
trx->state = DECT_TRANSCEIVER_STOPPED;
}
void dect_transceiver_enable(struct dect_transceiver *trx)
{
if (trx->mode == DECT_TRANSCEIVER_MASTER)
trx->state = DECT_TRANSCEIVER_LOCKED;
else {
trx->state = DECT_TRANSCEIVER_UNLOCKED;
trx->slots[DECT_SCAN_SLOT].state = DECT_SLOT_SCANNING;
}
trx->ops->enable(trx);
}
void dect_transceiver_confirm(struct dect_transceiver *trx)
{
trx_debug(trx, "confirm\n");
trx->state = DECT_TRANSCEIVER_LOCK_PENDING;
trx->slots[DECT_SCAN_SLOT].state = DECT_SLOT_RX;
trx->ops->confirm(trx);
}
void dect_transceiver_unlock(struct dect_transceiver *trx)
{
trx_debug(trx, "unlock\n");
trx->ops->unlock(trx);
trx->slots[DECT_SCAN_SLOT].state = DECT_SLOT_SCANNING;
trx->state = DECT_TRANSCEIVER_UNLOCKED;
}
int dect_transceiver_set_band(struct dect_transceiver *trx, u8 bandnum)
{
const struct dect_band *band;
band = dect_band[bandnum];
if (band == NULL)
return -ENOENT;
trx->carriers = trx->ops->set_band(trx, band);
trx->band = band;
return 0;
}
void dect_transceiver_lock(struct dect_transceiver *trx, u8 slot)
{
trx_debug(trx, "lock to slot %u\n", slot);
trx->slots[DECT_SCAN_SLOT].state = DECT_SLOT_IDLE;
trx->state = DECT_TRANSCEIVER_LOCKED;
trx->ops->lock(trx, slot);
}
bool dect_transceiver_channel_available(const struct dect_transceiver *trx,
const struct dect_channel_desc *chd)
{
if (trx->slots[chd->slot].state == DECT_SLOT_RX ||
trx->slots[chd->slot].state == DECT_SLOT_TX)
return false;
switch ((int)chd->pkt) {
case DECT_PACKET_P80:
if (trx->blind_full_slots & (1 << (chd->slot + 1)))
return false;
case DECT_PACKET_P32:
case DECT_PACKET_P08:
case DECT_PACKET_P00:
if (trx->blind_full_slots & (1 << chd->slot))
return false;
break;
}
return true;
}
static bool dect_tg_update_blind_full_slots(struct dect_transceiver_group *trg)
{
const struct dect_transceiver *trx;
u32 blind_full_slots;
blind_full_slots = (~0U) & DECT_SLOT_MASK;
dect_foreach_transceiver(trx, trg)
blind_full_slots &= trx->blind_full_slots;
if (trg->blind_full_slots != blind_full_slots) {
trg->blind_full_slots = blind_full_slots;
return true;
} else
return false;
}
/**
* dect_transceiver_reserve - reserve transceiver resources for a physical channel
*
* Reserve the slot positions necessary to estabish the specified physical
* channel. The chosen transceivers and the global groups blind full slot
* masks are updated.
*
* Returns true when the global visibility state has changed.
*/
bool dect_transceiver_reserve(struct dect_transceiver_group *trg,
struct dect_transceiver *trx,
const struct dect_channel_desc *chd)
{
switch ((int)chd->pkt) {
case DECT_PACKET_P80:
trx->blind_full_slots |= 1 << (chd->slot + 1);
case DECT_PACKET_P32:
case DECT_PACKET_P08:
case DECT_PACKET_P00:
trx->blind_full_slots |= 1 << chd->slot;
break;
}
return dect_tg_update_blind_full_slots(trg);
}
/**
* dect_transceiver_release - release transceiver resources of a phyiscal channel
*
* Release the slot positions used by the specified physical channel. The
* transceiver and the global group blind full slot masks are updated.
*
* Returns true when the global visibility state has changed.
*/
bool dect_transceiver_release(struct dect_transceiver_group *trg,
struct dect_transceiver *trx,
const struct dect_channel_desc *chd)
{
switch ((int)chd->pkt) {
case DECT_PACKET_P80:
trx->blind_full_slots &= ~(1 << (chd->slot + 1));
case DECT_PACKET_P32:
case DECT_PACKET_P08:
case DECT_PACKET_P00:
trx->blind_full_slots &= ~(1 << chd->slot);
break;
}
return dect_tg_update_blind_full_slots(trg);
}
void dect_register_notifier(struct notifier_block *nb)
{
dect_lock();
raw_notifier_chain_register(&dect_transceiver_chain, nb);
dect_unlock();
}
void dect_unregister_notifier(struct notifier_block *nb)
{
dect_lock();
raw_notifier_chain_unregister(&dect_transceiver_chain, nb);
dect_unlock();
}
static void dect_transceiver_notify(unsigned long val,
struct dect_transceiver *trx)
{
raw_notifier_call_chain(&dect_transceiver_chain, val, trx);
}
struct dect_transceiver *dect_transceiver_alloc(const struct dect_transceiver_ops *ops,
unsigned int priv)
{
struct dect_transceiver *trx;
unsigned int nevents, size, i;
/* Allocate enough event structures for one TDMA half frame */
nevents = DECT_HALF_FRAME_SIZE / ops->eventrate;
size = nevents * sizeof(trx->event[0]) + priv;
trx = kzalloc(sizeof(*trx) + size, GFP_KERNEL);
if (trx == NULL)
return NULL;
trx->state = DECT_TRANSCEIVER_STOPPED;
trx->ops = ops;
trx->blind_full_slots = ~ops->slotmask & DECT_SLOT_MASK;
for (i = 0; i < DECT_FRAME_SIZE; i++)
trx->slots[i].chd.slot = i;
for (i = 0; i < nevents; i++) {
skb_queue_head_init(&trx->event[i].rx_queue);
trx->event[i].trx = trx;
}
return trx;
}
EXPORT_SYMBOL_GPL(dect_transceiver_alloc);
void dect_transceiver_free(struct dect_transceiver *trx)
{
kfree(trx);
}
EXPORT_SYMBOL_GPL(dect_transceiver_free);
static int dect_transceiver_alloc_name(struct dect_transceiver *trx)
{
struct dect_transceiver *t;
unsigned long *inuse;
int i;
inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
if (inuse == NULL)
return -ENOMEM;
list_for_each_entry(t, &dect_transceiver_list, list) {
if (!sscanf(t->name, "trx%d", &i))
continue;
if (i > BITS_PER_BYTE * PAGE_SIZE)
continue;
set_bit(i, inuse);
}
i = find_first_zero_bit(inuse, BITS_PER_BYTE * PAGE_SIZE);
free_page((unsigned long)inuse);
if (i == BITS_PER_BYTE * PAGE_SIZE)
return -ENFILE;
snprintf(trx->name, sizeof(trx->name), "trx%d", i);
return 0;
}
int dect_register_transceiver(struct dect_transceiver *trx)
{
int err;
dect_lock();
err = dect_transceiver_alloc_name(trx);
if (err < 0)
goto out;
err = dect_transceiver_set_band(trx, DECT_DEFAULT_BAND);
if (err < 0)
goto out;
list_add_tail(&trx->list, &dect_transceiver_list);
dect_transceiver_notify(DECT_TRANSCEIVER_REGISTER, trx);
out:
dect_unlock();
return err;
}
EXPORT_SYMBOL_GPL(dect_register_transceiver);
void dect_unregister_transceiver(struct dect_transceiver *trx)
{
dect_lock();
list_del(&trx->list);
dect_transceiver_notify(DECT_TRANSCEIVER_UNREGISTER, trx);
dect_unlock();
synchronize_rcu();
trx->ops->destructor(trx);
}
EXPORT_SYMBOL_GPL(dect_unregister_transceiver);
/*
* RF-bands:
*/
struct dect_band_desc {
u8 band;
u8 carriers;
s16 c1_off;
u8 c2;
s16 c2_off;
};
static const struct dect_band_desc dect_band_desc[] __initdata = {
/* 1880 MHz to 1900 MHz RF band 00000 */
{ 0, 10, 0, -1, 0, },
/* 1880 MHz to 1978 MHz and 2010 MHz to 2025 MHz RF band 00001 */
{ 1, 64, 0, 56, 19, },
/* 1880 MHz to 1925 MHz and 2010 MHz to 2025 MHz RF band 00010 */
{ 2, 33, 0, 25, 50, },
/* 1880 MHz to 1900 MHz, 1915 MHz to 1940 MHz and 2010 MHz to
* 2025 MHz RF band 00011 */
{ 3, 33, 10, 25, 50, },
/* 1880 MHz to 1900 MHz, 1935 MHz to 1960 MHz and 2010 MHz to
* 2025 MHz RF band 00100 */
{ 4, 33, 22, 25, 50, },
/* 1880 MHz to 1900 MHZ, 1955 MHz to 1980 MHz and 2010 MHz to
* 2025 MHz RF band 00101 */
{ 5, 33, 34, 25, 50, },
/* 902 MHz to 928 MHz RF band 01000 */
{ 8, 24, -576, -1, 0, },
/* 2400 MHz to 2483,5 MHz RF band 01001 */
{ 9, 55, 292, -1, 0, },
};
/*
* A nominal DECT RF carrier is one whose center frequency is generated by
* the formula:
*
* Fg = F0 - g × 1,728 MHz, where g is any integer
*/
static u32 __init dect_calc_frequency(s16 g)
{
if (g >= 0 && g < 10)
return DECT_FREQUENCY_F0 - g * DECT_CARRIER_WIDTH;
else
return DECT_FREQUENCY_F0 + (g - 9) * DECT_CARRIER_WIDTH;
}
static int __init dect_init_band(const struct dect_band_desc *desc)
{
struct dect_band *band;
unsigned int size;
u8 carrier;
size = sizeof(*band) + desc->carriers * sizeof(band->frequency[0]);
band = kmalloc(size, GFP_KERNEL);
if (band == NULL)
return -ENOMEM;
band->band = desc->band;
band->carriers = desc->carriers;
for (carrier = 0; carrier < 10; carrier++)
band->frequency[carrier] =
dect_calc_frequency(carrier);
for (; carrier < min(desc->carriers, desc->c2); carrier++)
band->frequency[carrier] =
dect_calc_frequency(carrier + desc->c1_off);
for (; carrier < desc->carriers; carrier++)
band->frequency[carrier] =
dect_calc_frequency(carrier + desc->c2_off);
printk("RF-band %u:\n", band->band);
for (carrier = 0; carrier < band->carriers; carrier++) {
printk(" carrier %u: %u.%.3uMHz\n", carrier,
band->frequency[carrier] / 1000,
band->frequency[carrier] % 1000);
}
printk("\n");
dect_band[band->band] = band;
return 0;
}
int __init dect_transceiver_module_init(void)
{
unsigned int i;
int err;
for (i = 0; i < ARRAY_SIZE(dect_band_desc); i++) {
err = dect_init_band(&dect_band_desc[i]);
if (err < 0)
goto err1;
}
return 0;
err1:
dect_transceiver_module_exit();
return err;
}
void dect_transceiver_module_exit(void)
{
u8 band;
for (band = 0; band < ARRAY_SIZE(dect_band); band++)
kfree(dect_band[band]);
}