lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Tue, 13 Aug 2013 11:08:41 +0200 From: Benedikt Spranger <b.spranger@...utronix.de> To: netdev@...r.kernel.org Cc: Alexander Frank <Alexander.Frank@...rspaecher.com>, Sebastian Andrzej Siewior <bigeasy@...utronix.de>, Benedikt Spranger <b.spranger@...utronix.de> Subject: [PATCH 6/7] net: add the AF_FLEXRAY protocol FlexRay is a networking technology used in automotive fields as successor of the Controller Area Network (CAN). It provides the core functionality and a RAW protocol driver. Signed-off-by: Benedikt Spranger <b.spranger@...utronix.de> --- Documentation/networking/00-INDEX | 2 + Documentation/networking/flexray.txt | 24 ++ include/linux/flexray.h | 168 ++++++++ include/linux/flexray/core.h | 45 +++ include/linux/flexray/dev.h | 64 +++ include/linux/socket.h | 4 +- include/uapi/linux/flexray/Kbuild | 4 + include/uapi/linux/flexray/flexcard_netlink.h | 53 +++ include/uapi/linux/flexray/netlink.h | 203 ++++++++++ include/uapi/linux/flexray/raw.h | 16 + include/uapi/linux/if_arp.h | 1 + include/uapi/linux/if_ether.h | 1 + net/Kconfig | 1 + net/Makefile | 1 + net/core/sock.c | 9 +- net/flexray/Kconfig | 28 ++ net/flexray/Makefile | 9 + net/flexray/af_flexray.c | 548 ++++++++++++++++++++++++++ net/flexray/af_flexray.h | 59 +++ net/flexray/proc.c | 196 +++++++++ net/flexray/raw.c | 446 +++++++++++++++++++++ 21 files changed, 1878 insertions(+), 4 deletions(-) create mode 100644 Documentation/networking/flexray.txt create mode 100644 include/linux/flexray.h create mode 100644 include/linux/flexray/core.h create mode 100644 include/linux/flexray/dev.h create mode 100644 include/uapi/linux/flexray/Kbuild create mode 100644 include/uapi/linux/flexray/flexcard_netlink.h create mode 100644 include/uapi/linux/flexray/netlink.h create mode 100644 include/uapi/linux/flexray/raw.h create mode 100644 net/flexray/Kconfig create mode 100644 net/flexray/Makefile create mode 100644 net/flexray/af_flexray.c create mode 100644 net/flexray/af_flexray.h create mode 100644 net/flexray/proc.c create mode 100644 net/flexray/raw.c diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index 18b64b2..1cb180e 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -74,6 +74,8 @@ fib_trie.txt - Level Compressed Trie (LC-trie) notes: a structure for routing. filter.txt - Linux Socket Filtering +flexray.txt + - FlexRay Protocol Family fore200e.txt - FORE Systems PCA-200E/SBA-200E ATM NIC driver info. framerelay.txt diff --git a/Documentation/networking/flexray.txt b/Documentation/networking/flexray.txt new file mode 100644 index 0000000..9c0b844 --- /dev/null +++ b/Documentation/networking/flexray.txt @@ -0,0 +1,24 @@ +============================================================================ + +flexray.txt + +Readme file for the FlexRay Protocol Family (aka Socket FlexRay) + +This file contains + + 1 Overview / What is Socket FlexRay + +============================================================================ + +1 Overview / What is Socket FlexRay +----------------------------------- + +The socket FlexRay package is an implementation of FlexRay protocols +for Linux. FlexRay is a networking technology used in automotive fields as +successor of the Controller Area Network (CAN). It is designed to be faster +and more reliable than CAN. +The Socket FlexRay implementation uses the Berkeley socket API, the Linux +network stack and implements the FlexRay device drivers as network interfaces. +The FlexRay socket API has been designed as similar as possible to the TCP/IP +protocols to allow programmers, familiar with network programming, to easily +learn how to use FlexRay sockets. diff --git a/include/linux/flexray.h b/include/linux/flexray.h new file mode 100644 index 0000000..75e07e8 --- /dev/null +++ b/include/linux/flexray.h @@ -0,0 +1,168 @@ +/* + * linux/flexray.h + * + * Definitions for FlexRay network layer (socket addr / FlexRay frame) + * + */ + +#ifndef FLEXRAY_H +#define FLEXRAY_H + +#include <linux/types.h> +#include <linux/socket.h> + +/* FlexRay kernel definitions */ + +/* special address description flags for the FLEXRAY_ID */ +#define FLEXRAY_PPI_FLAG 0x40 /* Payload preamble indicator */ +#define FLEXRAY_NFI_FLAG 0x20 /* Null frame indikator */ +#define FLEXRAY_SYN_FLAG 0x10 /* Sync frame indikator */ +#define FLEXRAY_SFI_FLAG 0x08 /* Startup frame indikator */ + +/* + * FlexRay Frame structure + * + * Bit 0 reserved + * Bit 1 Payload preamble indicator + * Bit 2 Null frame indikator + * Bit 3 Sync frame indikator + * Bit 4 Startup frame indikator + * Bit 5-15 Frame ID + * Bit 16-22 Payload length + * Bit 23-33 Header CRC + * Bit 34-39 Cycle count + * PAYLOAD [0-254 Bytes] + * 24 Bit CRC + */ + +/* define Flexray Header Type for Filters */ +typedef __u64 flexray_header_t; + +/** + * struct flexray_frame - basic FlexRay frame structure + * @head: Header + * @data: the FlexRay frame payload. + * @crc: the FlexRay frame CRC + */ + +struct flexray_frame { + __u8 head[5]; + __u8 data[254] __aligned(8); + __u8 crc[3]; +}; + +static inline int flexray_get_ppi(__u8 *head) +{ + return !!(head[0] & FLEXRAY_PPI_FLAG); +} + +static inline void flexray_set_ppi(int ppi, __u8 *head) +{ + if (ppi) + head[0] |= FLEXRAY_PPI_FLAG; + else + head[0] &= ~FLEXRAY_PPI_FLAG; +} + +static inline int flexray_get_nfi(__u8 *head) +{ + return !!(head[0] & FLEXRAY_NFI_FLAG); +} + +static inline void flexray_set_nfi(int nfi, __u8 *head) +{ + if (nfi) + head[0] |= FLEXRAY_NFI_FLAG; + else + head[0] &= ~FLEXRAY_NFI_FLAG; +} + +static inline int flexray_get_syn(__u8 *head) +{ + return !!(head[0] & FLEXRAY_SYN_FLAG); +} + +static inline void flexray_set_syn(int syn, __u8 *head) +{ + if (syn) + head[0] |= FLEXRAY_SYN_FLAG; + else + head[0] &= ~FLEXRAY_SYN_FLAG; +} + +static inline int flexray_get_sfi(__u8 *head) +{ + return !!(head[0] & FLEXRAY_SFI_FLAG); +} + +static inline void flexray_set_sfi(int sfi, __u8 *head) +{ + if (sfi) + head[0] |= FLEXRAY_SFI_FLAG; + else + head[0] &= ~FLEXRAY_SFI_FLAG; +} + +static inline __u16 flexray_get_id(__u8 *head) +{ + return ((head[0] & 0x3) << 8) | head[1]; +} + +static inline void flexray_set_id(__u16 id, __u8 *head) +{ + head[0] &= ~0x3; + head[0] |= (id >> 8) & 0x3; + head[1] = id & 0xff; +} + +static inline __u8 flexray_get_pl(__u8 *head) +{ + return head[2] >> 1; +} + +static inline void flexray_set_pl(__u8 pl, __u8 *head) +{ + head[2] &= 0x1; + head[2] |= pl << 1; +} + +static inline __u16 flexray_get_hcrc(__u8 *head) +{ + return ((head[2] & 0x1) << 10) | (head[3] << 2) | (head[4] >> 6); +} + +static inline void flexray_set_hcrc(__u16 hcrc, __u8 *head) +{ + head[2] &= 0xfe; + head[4] &= 0x3f; + head[2] |= (hcrc >> 10) & 0x1; + head[3] = (hcrc >> 2) & 0xff; + head[4] |= (hcrc & 0x3) << 6; +} + +static inline __u8 flexray_get_cc(__u8 *head) +{ + return head[4] & 0x3f; +} + +static inline void flexray_set_cc(__u8 cc, __u8 *head) +{ + head[4] &= ~0x3f; + head[4] |= cc & 0x3f; +} + +/* particular protocols of the protocol family PF_FLEXRAY */ +#define FLEXRAY_RAW 1 /* RAW sockets */ +#define FLEXRAY_NPROTO 2 + +struct sockaddr_flexray { + sa_family_t flexray_family; + int flexray_ifindex; +}; + +struct flexray_filter { + flexray_header_t flexray_id; + flexray_header_t flexray_mask; +}; + +#endif /* FLEXRAY_H */ diff --git a/include/linux/flexray/core.h b/include/linux/flexray/core.h new file mode 100644 index 0000000..90a0f06 --- /dev/null +++ b/include/linux/flexray/core.h @@ -0,0 +1,45 @@ +/* + * Copyright 2012 Eberspächer Electronics GmbH & Co. KG. All Rights Reserved. + */ + +#ifndef FLEXRAY_CORE_H +#define FLEXRAY_CORE_H + +#include <linux/flexray.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> + +#define DNAME(dev) ((dev) ? (dev)->name : "any") + +/** + * struct flexray_proto - FlexRay protocol structure + * @type: type argument in socket() syscall, e.g. SOCK_DGRAM. + * @protocol: protocol number in socket() syscall. + * @ops: pointer to struct proto_ops for sock->ops. + * @prot: pointer to struct proto structure. + */ +struct flexray_proto { + int type; + int protocol; + const struct proto_ops *ops; + struct proto *prot; +}; + +/* function prototypes for the FlexRay networklayer core (af_flexray.c) */ + +extern int flexray_proto_register(const struct flexray_proto *frp); +extern void flexray_proto_unregister(const struct flexray_proto *frp); + +extern int flexray_rx_register(struct net_device *dev, + void (*func)(struct sk_buff *, void *), + void *data, char *ident); + +extern void flexray_rx_unregister(struct net_device *dev, + void (*func)(struct sk_buff *, void *), + void *data); + +extern int flexray_send(struct sk_buff *skb); +extern int flexray_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg); + +#endif /* FLEXRAY_CORE_H */ diff --git a/include/linux/flexray/dev.h b/include/linux/flexray/dev.h new file mode 100644 index 0000000..999ebab --- /dev/null +++ b/include/linux/flexray/dev.h @@ -0,0 +1,64 @@ +/* + * Copyright 2012 Eberspächer Electronics GmbH & Co. KG. All Rights Reserved. + */ + +#ifndef FLEXRAY_DEV_H +#define FLEXRAY_DEV_H + +#include <linux/flexray.h> +#include <linux/flexray/netlink.h> + +/* FlexRay common private data */ + +struct flexray_priv { + struct flexray_device_stats flexray_stats; + + enum flexray_state state; + + int (*do_get_state)(const struct net_device *dev, + enum flexray_state *state); + int (*do_set_state)(struct net_device *dev, + enum flexray_state state); + int (*do_validate)(struct sk_buff *skb); + + struct flexray_cluster_param cluster; + struct flexray_node_param node; + struct flexray_symbol_param symbol; + __u32 sw_filter[FLEXRAY_MAX_SW_FILTER]; + u8 version; +}; + +/* Drop a given socketbuffer if it does not contain a valid FlexRay frame. */ +static inline int flexray_dropped_invalid_skb(struct net_device *dev, + struct sk_buff *skb) +{ + const struct flexray_frame *frf = (struct flexray_frame *)skb->data; + + if (unlikely(skb->len != sizeof(*frf))) { + kfree_skb(skb); + dev->stats.tx_dropped++; + return 1; + } + + return 0; +} + +struct net_device *alloc_flexraydev(int sizeof_priv, u8 version); +void free_flexraydev(struct net_device *dev); + +int open_flexraydev(struct net_device *dev); +void close_flexraydev(struct net_device *dev); + +int register_flexraydev(struct net_device *dev); +void unregister_flexraydev(struct net_device *dev); + +int flexray_restart_now(struct net_device *dev); + +struct sk_buff *alloc_flexray_skb(struct net_device *dev, + struct flexray_frame **cf); + +void print_cluster_config(struct flexray_cluster_param *cp, int is_v3); +void print_node_config(struct flexray_node_param *np, int is_v3); +void print_symbol_config(struct flexray_symbol_param *sp); + +#endif /* FLEXRAY_DEV_H */ diff --git a/include/linux/socket.h b/include/linux/socket.h index 230c04b..a7c316b 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -180,7 +180,8 @@ struct ucred { #define AF_ALG 38 /* Algorithm sockets */ #define AF_NFC 39 /* NFC sockets */ #define AF_VSOCK 40 /* vSockets */ -#define AF_MAX 41 /* For now.. */ +#define AF_FLEXRAY 41 /* Flexray */ +#define AF_MAX 42 /* For now.. */ /* Protocol families, same as address families. */ #define PF_UNSPEC AF_UNSPEC @@ -225,6 +226,7 @@ struct ucred { #define PF_ALG AF_ALG #define PF_NFC AF_NFC #define PF_VSOCK AF_VSOCK +#define PF_FLEXRAY AF_FLEXRAY #define PF_MAX AF_MAX /* Maximum queue length specifiable by listen. */ diff --git a/include/uapi/linux/flexray/Kbuild b/include/uapi/linux/flexray/Kbuild new file mode 100644 index 0000000..8c45658 --- /dev/null +++ b/include/uapi/linux/flexray/Kbuild @@ -0,0 +1,4 @@ +header-y += error.h +header-y += netlink.h +header-y += raw.h +header-y += flexcard_netlink.h diff --git a/include/uapi/linux/flexray/flexcard_netlink.h b/include/uapi/linux/flexray/flexcard_netlink.h new file mode 100644 index 0000000..d04e2dd --- /dev/null +++ b/include/uapi/linux/flexray/flexcard_netlink.h @@ -0,0 +1,53 @@ +/* + * Copyright 2012 Eberspächer Electronics GmbH & Co. KG. All Rights Reserved. + */ + +#ifndef _FLEXCARD_NETLINK_H +#define _FLEXCARD_NETLINK_H + +#include <linux/types.h> + +#define FC_MSGBUF_VERSION 1 + +/* Start Flexcard flags beyond ERAY flags */ +#define FC_MSGBUF_ACK 0x00010000 +#define FC_MSGBUF_ACK_NULL 0x00020000 +#define FC_MSGBUF_ACK_PAYLOAD 0x00040000 +#define FC_MSGBUF_SELFSYNC 0x00080000 + +struct fc_msgbuf_cfg { + __u32 flags; + __u8 buf_id; + __u8 cyc; + __u16 len; + __u16 max; + __u16 start; + __u32 frame_id; + __u32 reject_mask; + enum eray_msgbuf_type type; + enum eray_msgbuf_channel channel; +} __packed; + +/* commands */ +enum fc_msgbuf_cmd { + FC_MSGBUF_CMD_UNSPEC, + FC_MSGBUF_CMD_GET_CFG, + FC_MSGBUF_CMD_SET_CFG, + FC_MSGBUF_CMD_RESET_CFG, + FC_MSGBUF_CMD_READ_CFG, + __FC_MSGBUF_CMD_MAX, +}; +#define FC_MSGBUF_CMD_MAX (__FC_MSGBUF_CMD_MAX - 1) + +/* attributes */ +enum fc_msgbuf_attr { + FC_MSGBUF_ATTR_UNSPEC, + FC_MSGBUF_ATTR_BUF_ID, + FC_MSGBUF_ATTR_DEV_ID, + FC_MSGBUF_ATTR_DEV_NAME, + FC_MSGBUF_ATTR_CFG, + __FC_MSGBUF_ATTR_MAX, +}; +#define FC_MSGBUF_ATTR_MAX (__FC_MSGBUF_ATTR_MAX - 1) + +#endif /* _FLEXCARD_NETLINK_H */ diff --git a/include/uapi/linux/flexray/netlink.h b/include/uapi/linux/flexray/netlink.h new file mode 100644 index 0000000..3d1dbaf --- /dev/null +++ b/include/uapi/linux/flexray/netlink.h @@ -0,0 +1,203 @@ +/* + * Copyright 2012 Eberspächer Electronics GmbH & Co. KG. All Rights Reserved. + */ + +#ifndef FLEXRAY_NETLINK_H +#define FLEXRAY_NETLINK_H + +#include <linux/types.h> + +#define FLEXRAY_MAX_SW_FILTER 2048 + +/* + * FlexRay operational and error states + */ +enum flexray_state { + FLEXRAY_STATE_UNSPEC, + FLEXRAY_STATE_DEFAULT_CONFIG, + FLEXRAY_STATE_CONFIG, + FLEXRAY_STATE_READY, + FLEXRAY_STATE_WAKEUP, + FLEXRAY_STATE_STARTUP, + FLEXRAY_STATE_NORMAL_ACTIVE, + FLEXRAY_STATE_NORMAL_PASSIVE, + FLEXRAY_STATE_HALT, + FLEXRAY_STATE_MONITOR_MODE, + FLEXRAY_STATE_COLDSTART, + FLEXRAY_STATE_MAX +}; + +/* + * FlexRay device statistics + */ +struct flexray_device_stats { + __u32 txack; + __u32 manage; + __u32 info; + __u32 status; + __u32 notify; +}; + +/* + * FlexRay netlink interface + */ +enum { + IFLA_FLEXRAY_UNSPEC, + IFLA_FLEXRAY_STATE, + IFLA_FLEXRAY_VERSION, + IFLA_FLEXRAY_CLUSTER, + IFLA_FLEXRAY_NODE, + IFLA_FLEXRAY_SYMBOL, + IFLA_FLEXRAY_SW_FILTER, + __IFLA_FLEXRAY_MAX +}; + +#define IFLA_FLEXRAY_MAX (__IFLA_FLEXRAY_MAX - 1) + +/* + * FlexRay filter netlink interface + */ +enum { + IFLA_FLEXRAY_FILTER_UNSPEC, + IFLA_FLEXRAY_FILTER_ENTRY, + __IFLA_FLEXRAY_FILTER_MAX +}; + +#define IFLA_FLEXRAY_FILTER_MAX (__IFLA_FLEXRAY_FILTER_MAX - 1) + +struct cluster_v2 { + __u16 gAssumedPrecision; + __u8 gdMaxInitializationError; + __u8 gdMaxMicrotick; + __u8 gdMaxPropagationDelay; + __u8 gdMinPropagationDelay; + __u8 gdWakeupSymbolRxIdle; + __u8 gdWakeupSymbolRxLow; + __u16 gdWakeupSymbolRxWindow; + __u8 gdWakeupSymbolTxIdle; + __u8 gdWakeupSymbolTxLow; + __u32 gOffsetCorrectionMax; + __u16 gOffsetCorrectionStart; + __u8 gSyncNodeMax; +}; + +struct cluster_v3 { + __u16 gClockDeviationMax; + __u8 gCycleCountMax; + __u8 gdIgnoreAfterTx; + __u8 gdSymbolWindowActionPointOffset; + __u8 gdWakeupRxIdle; + __u8 gdWakeupRxLow; + __u16 gdWakeupRxWindow; + __u8 gdWakeupTxActive; + __u8 gdWakeupTxIdle; + __u8 gExternOffsetCorrection; + __u8 gExternRateCorrection; + __u8 gSyncFrameIDCountMax; +}; + +struct flexray_cluster_param { + /* Protocol relevant */ + __u8 gColdstartAttempts; + __u8 gdActionPointOffset; + __u8 gdCASRxLowMax; + __u8 gdDynamicSlotIdlePhase; + __u8 gdMinislot; + __u8 gdMinislotActionPointOffset; + __u16 gdStaticSlot; + __u8 gdSymbolWindow; + __u8 gdTSSTransmitter; + __u8 gListenNoise; + __u16 gMacroPerCycle; + __u8 gMaxWithoutClockCorrectionFatal; + __u8 gMaxWithoutClockCorrectionPassive; + __u16 gNumberOfMinislots; + __u16 gNumberOfStaticSlots; + __u8 gPayloadLengthStatic; + + /* Protocol related */ + __u8 gChannels; + __u8 gClusterDriftDamping; + __u8 gdBit; + __u16 gdCycle; + __u8 gdMacrotick; + __u16 gdNIT; + __u8 gdSampleClockPeriod; + __u8 gNetworkManagementVectorLength; + union { + struct cluster_v2 v2; + struct cluster_v3 v3; + }; +}; + +struct node_v2 { + __u16 pdMaxDrift; + __u8 pMicroPerMacroNom; + __u8 pSingleSlotEnabled; +}; + +struct node_v3 { + __u8 pExternalSync; + __u8 pFallBackInternal; + __u8 pKeySlotOnlyEnabled; + __u8 pNMVectorEarlyUpdate; + __u8 pOffsetCorrectionStart; + __u8 pSecondKeySlotID; + __u8 pTwoKeySlotMode; +}; + +struct flexray_node_param { + /* Protocol relevant */ + __u8 pAllowHaltDueToClock; + __u8 pAllowPassiveToActive; + __u8 pChannels; + __u8 pClusterDriftDamping; + __u16 pdAcceptedStartupRange; + __u8 pDecodingCorrection; + __u8 pDelayCompensationA; + __u8 pDelayCompensationB; + __u32 pdListenTimeout; + __s8 vExternOffsetControl; + __s8 vExternRateControl; + __u8 pExternOffsetCorrection; + __u8 pExternRateCorrection; + __u16 pKeySlotID; + __u8 pKeySlotUsedForStartup; + __u8 pKeySlotUsedForSync; + __u16 pLatestTx; + __u8 pMacroInitialOffsetA; + __u8 pMacroInitialOffsetB; + __u16 pMicroInitialOffsetA; + __u16 pMicroInitialOffsetB; + __u32 pMicroPerCycle; + __u16 pOffsetCorrectionOut; + __u16 pRateCorrectionOut; + __u8 pWakeupChannel; + __u8 pWakeupPattern; + + /* Protocol related */ + __u8 pdMicrotick; + __u8 pPayloadLengthDynMax; + __u8 pSamplesPerMicrotick; + + union { + struct node_v2 v2; + struct node_v3 v3; + }; +}; + +struct flexray_symbol_param { + /* Protocol related */ + __u8 pChannelsMTS; +}; + +/* + * FlexRay software ID filter + */ + +struct flexray_sw_filter { + __u32 pos; + __u32 id; +}; + +#endif /* FLEXRAY_NETLINK_H */ diff --git a/include/uapi/linux/flexray/raw.h b/include/uapi/linux/flexray/raw.h new file mode 100644 index 0000000..0b12068 --- /dev/null +++ b/include/uapi/linux/flexray/raw.h @@ -0,0 +1,16 @@ +/* + * Copyright 2012 Eberspächer Electronics GmbH & Co. KG. All Rights Reserved. + */ + +#ifndef FLEXRAY_RAW_H +#define FLEXRAY_RAW_H + +#include <linux/flexray.h> + +/* for socket options affecting the socket (not the global system) */ + +enum { + FLEXRAY_RAW_FILTER = 1, /* set 0 .. n can_filter(s) */ +}; + +#endif diff --git a/include/uapi/linux/if_arp.h b/include/uapi/linux/if_arp.h index d7fea34..d64971f 100644 --- a/include/uapi/linux/if_arp.h +++ b/include/uapi/linux/if_arp.h @@ -53,6 +53,7 @@ #define ARPHRD_X25 271 /* CCITT X.25 */ #define ARPHRD_HWX25 272 /* Boards with X.25 in firmware */ #define ARPHRD_CAN 280 /* Controller Area Network */ +#define ARPHRD_FLEXRAY 290 /* FlexRay */ #define ARPHRD_PPP 512 #define ARPHRD_CISCO 513 /* Cisco HDLC */ #define ARPHRD_HDLC ARPHRD_CISCO diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h index ade07f1..05e886e 100644 --- a/include/uapi/linux/if_ether.h +++ b/include/uapi/linux/if_ether.h @@ -112,6 +112,7 @@ #define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */ #define ETH_P_CAN 0x000C /* CAN: Controller Area Network */ #define ETH_P_CANFD 0x000D /* CANFD: CAN flexible data rate*/ +#define ETH_P_FLEXRAY 0x000F /* Flexray */ #define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/ #define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ #define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@...e.net) */ diff --git a/net/Kconfig b/net/Kconfig index ee02136..8b7e604 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -328,6 +328,7 @@ endmenu source "net/ax25/Kconfig" source "net/can/Kconfig" +source "net/flexray/Kconfig" source "net/irda/Kconfig" source "net/bluetooth/Kconfig" source "net/rxrpc/Kconfig" diff --git a/net/Makefile b/net/Makefile index 9492e8c..8d03e63 100644 --- a/net/Makefile +++ b/net/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_NETROM) += netrom/ obj-$(CONFIG_ROSE) += rose/ obj-$(CONFIG_AX25) += ax25/ obj-$(CONFIG_CAN) += can/ +obj-$(CONFIG_FLEXRAY) += flexray/ obj-$(CONFIG_IRDA) += irda/ obj-$(CONFIG_BT) += bluetooth/ obj-$(CONFIG_SUNRPC) += sunrpc/ diff --git a/net/core/sock.c b/net/core/sock.c index 83667de..820e44e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -213,7 +213,8 @@ static const char *const af_family_key_strings[AF_MAX+1] = { "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_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG" , - "sk_lock-AF_NFC" , "sk_lock-AF_VSOCK" , "sk_lock-AF_MAX" + "sk_lock-AF_NFC" , "sk_lock-AF_VSOCK" , "sk_lock-AF_FLEXRAY" , + "sk_lock-AF_MAX" }; static const char *const af_family_slock_key_strings[AF_MAX+1] = { "slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" , @@ -229,7 +230,8 @@ static const char *const af_family_slock_key_strings[AF_MAX+1] = { "slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" , "slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" , "slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG" , - "slock-AF_NFC" , "slock-AF_VSOCK" ,"slock-AF_MAX" + "slock-AF_NFC" , "slock-AF_VSOCK" , "slock-AF_FLEXRAY" , + "slock-AF_MAX" }; static const char *const af_family_clock_key_strings[AF_MAX+1] = { "clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" , @@ -245,7 +247,8 @@ static const char *const af_family_clock_key_strings[AF_MAX+1] = { "clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" , "clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" , "clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG" , - "clock-AF_NFC" , "clock-AF_VSOCK" , "clock-AF_MAX" + "clock-AF_NFC" , "clock-AF_VSOCK" , "clock-AF_FLEXRAY" , + "clock-AF_MAX" }; /* diff --git a/net/flexray/Kconfig b/net/flexray/Kconfig new file mode 100644 index 0000000..18d9d69 --- /dev/null +++ b/net/flexray/Kconfig @@ -0,0 +1,28 @@ +# +# FlexRay network layer core configuration +# + +menuconfig FLEXRAY + depends on NET + tristate "FlexRay bus subsystem support" + ---help--- + FlexRay is a slow (up to 10Mbit/s) serial communications + protocol which was developed by the FlexRay Consortium, a + cooperation of leading companies in the automotive industry, from + 2000 till 2010, which result in ISO 10681. + More information on the FlexRay network protocol family PF_FLEXRAY + is contained in <Documentation/networking/flexray.txt>. + + If you want FLEXRAY support you should say Y here and also to the + specific driver for your controller(s) below. + +config FLEXRAY_RAW + tristate "Raw FlexRay Protocol" + depends on FLEXRAY + default N + ---help--- + The raw FlexRay protocol option offers access to the FlexRay bus + via the BSD socket API. You probably want to use the raw socket in + most cases where no higher level protocol is being used. + To receive/send raw FLEXRAY messages, use AF_FLEXRAY with protocol + FLEXRAY_RAW. diff --git a/net/flexray/Makefile b/net/flexray/Makefile new file mode 100644 index 0000000..f5e05b6c --- /dev/null +++ b/net/flexray/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the Linux FlexRay core. +# + +obj-$(CONFIG_FLEXRAY) += flexray.o +flexray-y := af_flexray.o proc.o + +obj-$(CONFIG_FLEXRAY_RAW) += flexray-raw.o +flexray-raw-y := raw.o diff --git a/net/flexray/af_flexray.c b/net/flexray/af_flexray.c new file mode 100644 index 0000000..e5fd1c4 --- /dev/null +++ b/net/flexray/af_flexray.c @@ -0,0 +1,548 @@ +/* Copyright 2012 Eberspächer Electronics GmbH & Co. KG. All Rights Reserved */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kmod.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/rcupdate.h> +#include <linux/uaccess.h> +#include <linux/net.h> +#include <linux/netdevice.h> +#include <linux/socket.h> +#include <linux/if_ether.h> +#include <linux/if_arp.h> +#include <linux/skbuff.h> +#include <linux/flexray.h> +#include <linux/flexray/core.h> +#include <linux/flexray/dev.h> +#include <linux/ratelimit.h> +#include <net/net_namespace.h> +#include <net/sock.h> + +#include "af_flexray.h" + +/* receive filters subscribed for 'all' FlexRay devices */ +struct dev_rcv_lists flexray_rx_alldev_list; +static DEFINE_SPINLOCK(flexray_rcvlists_lock); + +static struct kmem_cache *rcv_cache __read_mostly; + +/* table of registered FlexRay protocols */ +static const struct flexray_proto *proto_tab[FLEXRAY_NPROTO] __read_mostly; +static DEFINE_MUTEX(proto_tab_lock); + +struct s_stats flexray_stats; /* packet statistics */ +struct s_pstats flexray_pstats; /* receive list statistics */ + +/* af_flexray socket functions */ + +int flexray_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + struct sock *sk = sock->sk; + + switch (cmd) { + + case SIOCGSTAMP: + return sock_get_timestamp(sk, (struct timeval __user *)arg); + + default: + return -ENOIOCTLCMD; + } +} +EXPORT_SYMBOL(flexray_ioctl); + +static void flexray_sock_destruct(struct sock *sk) +{ + skb_queue_purge(&sk->sk_receive_queue); +} + +static const struct flexray_proto *flexray_get_proto(int protocol) +{ + const struct flexray_proto *frp; + + rcu_read_lock(); + frp = rcu_dereference(proto_tab[protocol]); + if (frp && !try_module_get(frp->prot->owner)) + frp = NULL; + rcu_read_unlock(); + + return frp; +} + +static inline void flexray_put_proto(const struct flexray_proto *frp) +{ + module_put(frp->prot->owner); +} + +static int flexray_create(struct net *net, struct socket *sock, int protocol, + int kern) +{ + struct sock *sk; + const struct flexray_proto *frp; + int err = 0; + + sock->state = SS_UNCONNECTED; + + if (protocol < 0 || protocol >= FLEXRAY_NPROTO) + return -EINVAL; + + if (!net_eq(net, &init_net)) + return -EAFNOSUPPORT; + + frp = flexray_get_proto(protocol); + +#ifdef CONFIG_MODULES + if (!frp) { + request_module("flexray-proto-%d", protocol); + frp = flexray_get_proto(protocol); + } +#endif + /* check for available protocol and correct usage */ + if (!frp) + return -EPROTONOSUPPORT; + + if (frp->type != sock->type) { + err = -EPROTOTYPE; + goto errout; + } + + sock->ops = frp->ops; + + sk = sk_alloc(net, PF_FLEXRAY, GFP_KERNEL, frp->prot); + if (!sk) { + err = -ENOMEM; + goto errout; + } + + sock_init_data(sock, sk); + sk->sk_destruct = flexray_sock_destruct; + + if (sk->sk_prot->init) + err = sk->sk_prot->init(sk); + + if (err) { + /* release sk on errors */ + sock_orphan(sk); + sock_put(sk); + } + +errout: + flexray_put_proto(frp); + return err; +} + +/** + * flexray_send - transmit a FlexRay frame + * @skb: pointer to socket buffer with FlexRay frame in data section + * + * Return: + * 0 on success + * -ENETDOWN when the selected interface is down + * -ENOBUFS on full driver queue (see net_xmit_errno()) + * -EPERM when trying to send on a non-FlexRay interface + * -EINVAL when the skb->data does not contain a valid FlexRay frame + * The skb is always consumed. + */ +int flexray_send(struct sk_buff *skb) +{ + struct flexray_priv *priv; + int err; + + priv = netdev_priv(skb->dev); + + if (skb->dev->type != ARPHRD_FLEXRAY) { + err = -EPERM; + goto err_skb; + } + + if (!(skb->dev->flags & IFF_UP)) { + err = -ENETDOWN; + goto err_skb; + } + + if (!priv->do_validate) { + err = -EINVAL; + goto err_skb; + } + + err = priv->do_validate(skb); + if (err) + goto err_skb; + + skb->protocol = htons(ETH_P_FLEXRAY); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); + + skb->pkt_type = PACKET_HOST; + + /* send to netdevice */ + err = dev_queue_xmit(skb); + if (err > 0) { + err = net_xmit_errno(err); + return err; + } + + /* update statistics */ + flexray_stats.tx_frames++; + + return 0; +err_skb: + kfree_skb(skb); + return err; +} +EXPORT_SYMBOL(flexray_send); + +/* af_flexray rx path */ + +static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev) +{ + if (!dev) + return &flexray_rx_alldev_list; + else + return (struct dev_rcv_lists *)dev->ml_priv; +} + +int flexray_rx_register(struct net_device *dev, + void (*func)(struct sk_buff *, void *), + void *data, char *ident) +{ + struct receiver *r; + struct dev_rcv_lists *d; + int err = 0; + + if (dev && dev->type != ARPHRD_FLEXRAY) + return -ENODEV; + + r = kmem_cache_alloc(rcv_cache, GFP_KERNEL); + if (!r) + return -ENOMEM; + + spin_lock(&flexray_rcvlists_lock); + + d = find_dev_rcv_lists(dev); + if (d) { + r->func = func; + r->data = data; + r->ident = ident; + + hlist_add_head_rcu(&r->list, &d->rx[RX_ALL]); + d->entries++; + + flexray_pstats.rcv_entries++; + if (flexray_pstats.rcv_entries_max < flexray_pstats.rcv_entries) + flexray_pstats.rcv_entries_max = + flexray_pstats.rcv_entries; + } else { + kmem_cache_free(rcv_cache, r); + err = -ENODEV; + } + + spin_unlock(&flexray_rcvlists_lock); + + return err; +} +EXPORT_SYMBOL(flexray_rx_register); + +static void flexray_rx_delete_receiver(struct rcu_head *rp) +{ + struct receiver *r = container_of(rp, struct receiver, rcu); + + kmem_cache_free(rcv_cache, r); +} + +void flexray_rx_unregister(struct net_device *dev, + void (*func)(struct sk_buff *, void *), void *data) +{ + struct receiver *r = NULL; + struct hlist_head *rl; + struct dev_rcv_lists *d; + bool found = false; + + if (dev && dev->type != ARPHRD_FLEXRAY) + return; + + spin_lock(&flexray_rcvlists_lock); + + d = find_dev_rcv_lists(dev); + if (!d) { + netdev_err(dev, "BUG: receive list not found\n"); + goto out; + } + + rl = &d->rx[RX_ALL]; + + /* Search the receiver list for the item to delete. This should + * exist, since no receiver may be unregistered that hasn't + * been registered before. + */ + + hlist_for_each_entry_rcu(r, rl, list) { + if (r->func == func && r->data == data) { + found = true; + break; + } + } + + if (!found) { + netdev_err(dev, "BUG: receive list entry not found\n"); + r = NULL; + goto out; + } + + hlist_del_rcu(&r->list); + d->entries--; + + if (flexray_pstats.rcv_entries > 0) + flexray_pstats.rcv_entries--; + + /* remove device structure requested by NETDEV_UNREGISTER */ + if (d->remove_on_zero_entries && !d->entries) { + kfree(d); + dev->ml_priv = NULL; + } + +out: + spin_unlock(&flexray_rcvlists_lock); + + /* schedule the receiver item for deletion */ + if (r) + call_rcu(&r->rcu, flexray_rx_delete_receiver); +} +EXPORT_SYMBOL(flexray_rx_unregister); + +static inline void deliver(struct sk_buff *skb, struct receiver *r) +{ + r->func(skb, r->data); +} + +static int flexray_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb) +{ + struct receiver *r; + int matches = 0; + + if (d->entries == 0) + return 0; + + /* check for unfiltered entries */ + hlist_for_each_entry_rcu(r, &d->rx[RX_ALL], list) { + deliver(skb, r); + matches++; + } + + return matches; +} + +static int flexray_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) +{ + struct dev_rcv_lists *d; + struct flexray_frame *frf = (struct flexray_frame *)skb->data; + int matches; + + if (!net_eq(dev_net(dev), &init_net)) + goto drop; + + if (WARN_ONCE(dev->type != ARPHRD_FLEXRAY, + "PF_FLEXRAY: dropped non conform skbuf: " + "dev type %d, len %d, payload %d\n", + dev->type, skb->len, flexray_get_pl(frf->head))) + goto drop; + + /* update statistics */ + flexray_stats.rx_frames++; + + rcu_read_lock(); + + /* deliver the packet to sockets listening on all devices */ + matches = flexray_rcv_filter(&flexray_rx_alldev_list, skb); + + /* find receive list for this device */ + d = find_dev_rcv_lists(dev); + if (d) + matches += flexray_rcv_filter(d, skb); + + rcu_read_unlock(); + + /* consume the skbuff allocated by the netdevice driver */ + consume_skb(skb); + + if (matches > 0) + flexray_stats.matches++; + + return NET_RX_SUCCESS; + +drop: + kfree_skb(skb); + return NET_RX_DROP; +} + +/* af_flexray protocol functions */ +int flexray_proto_register(const struct flexray_proto *frp) +{ + int proto = frp->protocol; + int err = 0; + + if (proto < 0 || proto >= FLEXRAY_NPROTO) { + pr_err("flexray: protocol number %d out of range\n", proto); + return -EINVAL; + } + + err = proto_register(frp->prot, 0); + if (err < 0) + return err; + + mutex_lock(&proto_tab_lock); + + if (proto_tab[proto]) { + pr_err("flexray: protocol %d already registered\n", + proto); + err = -EBUSY; + } else + rcu_assign_pointer(proto_tab[proto], frp); + + mutex_unlock(&proto_tab_lock); + + if (err < 0) + proto_unregister(frp->prot); + + return err; +} +EXPORT_SYMBOL(flexray_proto_register); + +void flexray_proto_unregister(const struct flexray_proto *frp) +{ + int proto = frp->protocol; + + mutex_lock(&proto_tab_lock); + BUG_ON(proto_tab[proto] != frp); + rcu_assign_pointer(proto_tab[proto], NULL); + mutex_unlock(&proto_tab_lock); + + synchronize_rcu(); + + proto_unregister(frp->prot); +} +EXPORT_SYMBOL(flexray_proto_unregister); + +/* af_flexray notifier to create/remove FlexRay netdevice specific structs */ +static int flexray_notifier(struct notifier_block *nb, unsigned long msg, + void *data) +{ + struct net_device *dev = (struct net_device *)data; + struct dev_rcv_lists *d; + + if (!net_eq(dev_net(dev), &init_net)) + return NOTIFY_DONE; + + if (dev->type != ARPHRD_FLEXRAY) + return NOTIFY_DONE; + + switch (msg) { + + case NETDEV_REGISTER: + /* create new dev_rcv_lists for this device */ + d = kzalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + netdev_err(dev, "allocation of receive list failed\n"); + return NOTIFY_DONE; + } + BUG_ON(dev->ml_priv); + dev->ml_priv = d; + + break; + + case NETDEV_UNREGISTER: + spin_lock(&flexray_rcvlists_lock); + + d = dev->ml_priv; + if (d) { + if (d->entries) + d->remove_on_zero_entries = 1; + else { + kfree(d); + dev->ml_priv = NULL; + } + } else + netdev_err(dev, "notifier: receive list not found\n"); + + spin_unlock(&flexray_rcvlists_lock); + break; + } + + return NOTIFY_DONE; +} + +/* af_flexray module init/exit functions */ + +static struct packet_type flexray_packet __read_mostly = { + .type = cpu_to_be16(ETH_P_FLEXRAY), + .func = flexray_rcv, +}; + +static const struct net_proto_family flexray_family_ops = { + .family = PF_FLEXRAY, + .create = flexray_create, + .owner = THIS_MODULE, +}; + +/* notifier block for netdevice event */ +static struct notifier_block flexray_netdev_notifier __read_mostly = { + .notifier_call = flexray_notifier, +}; + +static __init int flexray_init(void) +{ + memset(&flexray_rx_alldev_list, 0, sizeof(flexray_rx_alldev_list)); + + rcv_cache = kmem_cache_create("flexray_receiver", + sizeof(struct receiver), 0, 0, NULL); + if (!rcv_cache) + return -ENOMEM; + + flexray_init_proc(); + + /* protocol register */ + sock_register(&flexray_family_ops); + register_netdevice_notifier(&flexray_netdev_notifier); + dev_add_pack(&flexray_packet); + return 0; +} +module_init(flexray_init); + +static __exit void flexray_exit(void) +{ + struct net_device *dev; + + flexray_remove_proc(); + + /* protocol unregister */ + dev_remove_pack(&flexray_packet); + unregister_netdevice_notifier(&flexray_netdev_notifier); + sock_unregister(PF_FLEXRAY); + + /* remove created dev_rcv_lists from still registered FlexRay devices */ + rcu_read_lock(); + for_each_netdev_rcu(&init_net, dev) { + if (dev->type == ARPHRD_FLEXRAY && dev->ml_priv) { + struct dev_rcv_lists *d = dev->ml_priv; + + BUG_ON(d->entries); + kfree(d); + dev->ml_priv = NULL; + } + } + rcu_read_unlock(); + + rcu_barrier(); /* Wait for completion of call_rcu()'s */ + + kmem_cache_destroy(rcv_cache); +} +module_exit(flexray_exit); + +MODULE_DESCRIPTION("FlexRay PF_FLEXRAY core"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Benedikt Spranger <b.spranger@...utronix.de>"); + +MODULE_ALIAS_NETPROTO(PF_FLEXRAY); diff --git a/net/flexray/af_flexray.h b/net/flexray/af_flexray.h new file mode 100644 index 0000000..5aec894 --- /dev/null +++ b/net/flexray/af_flexray.h @@ -0,0 +1,59 @@ +/* Copyright 2012 Eberspächer Electronics GmbH & Co. KG. All Rights Reserved */ + +#ifndef AF_FLEXRAY_H +#define AF_FLEXRAY_H + +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/list.h> +#include <linux/rcupdate.h> +#include <linux/flexray.h> + +/* af_flexray rx dispatcher structures */ + +struct receiver { + struct hlist_node list; + struct rcu_head rcu; + void (*func)(struct sk_buff *, void *); + void *data; + char *ident; +}; + +enum {RX_ALL, RX_MAX}; + +/* per device receive filters linked at dev->ml_priv */ +struct dev_rcv_lists { + struct hlist_head rx[RX_MAX]; + struct hlist_head rx_sff[0x800]; + int remove_on_zero_entries; + int entries; +}; + +/* can be reset e.g. by flexray_init_stats() */ +struct s_stats { + unsigned long rx_frames; + unsigned long tx_frames; + unsigned long matches; +}; + +/* persistent statistics */ +struct s_pstats { + unsigned long stats_reset; + unsigned long user_reset; + unsigned long rcv_entries; + unsigned long rcv_entries_max; +}; + +/* function prototypes for the FlexRay networklayer procfs (proc.c) */ +extern void flexray_init_proc(void); +extern void flexray_remove_proc(void); +extern void flexray_stat_update(unsigned long data); + +/* structures and variables from af_flexray.c needed in proc.c for reading */ +extern struct s_stats flexray_stats; /* packet statistics */ +extern struct s_pstats flexray_pstats; /* receive list statistics */ +extern struct hlist_head flexray_rx_dev_list; /* rx dispatcher structures */ +/* receive filters subscribed for 'all' FlexRay devices */ +extern struct dev_rcv_lists flexray_rx_alldev_list; + +#endif /* AF_FLEXRAY_H */ diff --git a/net/flexray/proc.c b/net/flexray/proc.c new file mode 100644 index 0000000..e82f844 --- /dev/null +++ b/net/flexray/proc.c @@ -0,0 +1,196 @@ +/* Copyright 2012 Eberspächer Electronics GmbH & Co. KG. All Rights Reserved */ + +#include <linux/module.h> +#include <linux/proc_fs.h> +#include <linux/list.h> +#include <linux/rcupdate.h> +#include <linux/if_arp.h> +#include <linux/flexray/core.h> + +#include "af_flexray.h" + +/* proc filenames for the PF_FLEXRAY core */ + +#define FLEXRAY_PROC_STATS "stats" +#define FLEXRAY_PROC_RESET_STATS "reset_stats" +#define FLEXRAY_PROC_RCVLIST_ALL "rcvlist_all" +#define FLEXRAY_PROC_RCVLIST_FIL "rcvlist_fil" + +static struct proc_dir_entry *flexray_dir; +static struct proc_dir_entry *pde_stats; +static struct proc_dir_entry *pde_reset_stats; +static struct proc_dir_entry *pde_rcvlist_all; + +static const char rx_list_name[][8] = { + [RX_ALL] = "rx_all", +}; + +static void flexray_print_rcvlist(struct seq_file *m, + struct hlist_head *rx_list, + struct net_device *dev) +{ + struct receiver *r; + + hlist_for_each_entry_rcu(r, rx_list, list) + seq_printf(m, " %-5s %pK %pK %s\n", + DNAME(dev), r->func, r->data, r->ident); +} + +static void flexray_print_recv_banner(struct seq_file *m) +{ + seq_puts(m, " device flexray_id flexray_mask function" + " userdata matches ident\n"); +} + +static int flexray_stats_proc_show(struct seq_file *m, void *v) +{ + seq_putc(m, '\n'); + seq_printf(m, " %8ld transmitted frames (TXF)\n", + flexray_stats.tx_frames); + seq_printf(m, " %8ld received frames (RXF)\n", + flexray_stats.rx_frames); + seq_printf(m, " %8ld matched frames (RXMF)\n", + flexray_stats.matches); + + seq_putc(m, '\n'); + + seq_printf(m, " %8ld current receive list entries (CRCV)\n", + flexray_pstats.rcv_entries); + seq_printf(m, " %8ld maximum receive list entries (MRCV)\n", + flexray_pstats.rcv_entries_max); + + if (flexray_pstats.stats_reset) + seq_printf(m, "\n %8ld statistic resets (STR)\n", + flexray_pstats.stats_reset); + + if (flexray_pstats.user_reset) + seq_printf(m, " %8ld user statistic resets (USTR)\n", + flexray_pstats.user_reset); + + seq_putc(m, '\n'); + return 0; +} + +static int flexray_stats_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, flexray_stats_proc_show, NULL); +} + +static const struct file_operations flexray_stats_proc_fops = { + .owner = THIS_MODULE, + .open = flexray_stats_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int flexray_reset_stats_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "Performed statistic reset #%ld.\n", + flexray_pstats.stats_reset); + + return 0; +} + +static int flexray_reset_stats_proc_open(struct inode *inode, + struct file *file) +{ + return single_open(file, flexray_reset_stats_proc_show, NULL); +} + +static const struct file_operations flexray_reset_stats_proc_fops = { + .owner = THIS_MODULE, + .open = flexray_reset_stats_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void flexray_rcvlist_proc_show_one(struct seq_file *m, int idx, + struct net_device *dev, + struct dev_rcv_lists *d) +{ + if (!hlist_empty(&d->rx[idx])) { + flexray_print_recv_banner(m); + flexray_print_rcvlist(m, &d->rx[idx], dev); + } else + seq_printf(m, " (%s: no entry)\n", DNAME(dev)); +} + +static int flexray_rcvlist_proc_show(struct seq_file *m, void *v) +{ + int idx = (int)(long)m->private; + struct net_device *dev; + struct dev_rcv_lists *d; + + seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]); + + rcu_read_lock(); + + /* receive list for 'all' FlexRay devices (dev == NULL) */ + d = &flexray_rx_alldev_list; + flexray_rcvlist_proc_show_one(m, idx, NULL, d); + + /* receive list for registered FlexRay devices */ + for_each_netdev_rcu(&init_net, dev) { + if (dev->type == ARPHRD_FLEXRAY && dev->ml_priv) + flexray_rcvlist_proc_show_one(m, idx, dev, + dev->ml_priv); + } + + rcu_read_unlock(); + + seq_putc(m, '\n'); + return 0; +} + +static int flexray_rcvlist_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, flexray_rcvlist_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations flexray_rcvlist_proc_fops = { + .owner = THIS_MODULE, + .open = flexray_rcvlist_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void flexray_remove_proc_readentry(const char *name) +{ + remove_proc_entry(name, flexray_dir); +} + +void flexray_init_proc(void) +{ + int perm = S_IRUGO | S_IWUSR; + + flexray_dir = proc_mkdir("flexray", init_net.proc_net); + if (!flexray_dir) + return; + + pde_stats = proc_create(FLEXRAY_PROC_STATS, perm, flexray_dir, + &flexray_stats_proc_fops); + pde_reset_stats = proc_create(FLEXRAY_PROC_RESET_STATS, perm, + flexray_dir, &flexray_reset_stats_proc_fops); + pde_rcvlist_all = proc_create_data(FLEXRAY_PROC_RCVLIST_ALL, perm, + flexray_dir, &flexray_rcvlist_proc_fops, + (void *)RX_ALL); +} + +void flexray_remove_proc(void) +{ + if (!flexray_dir) + return; + if (pde_stats) + flexray_remove_proc_readentry(FLEXRAY_PROC_STATS); + + if (pde_reset_stats) + flexray_remove_proc_readentry(FLEXRAY_PROC_RESET_STATS); + + if (pde_rcvlist_all) + flexray_remove_proc_readentry(FLEXRAY_PROC_RCVLIST_ALL); + + remove_proc_entry("flexray", init_net.proc_net); +} diff --git a/net/flexray/raw.c b/net/flexray/raw.c new file mode 100644 index 0000000..78fd0de --- /dev/null +++ b/net/flexray/raw.c @@ -0,0 +1,446 @@ +/* Copyright 2012 Eberspächer Electronics GmbH & Co. KG. All Rights Reserved */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/uio.h> +#include <linux/net.h> +#include <linux/slab.h> +#include <linux/netdevice.h> +#include <linux/socket.h> +#include <linux/if_arp.h> +#include <linux/skbuff.h> +#include <linux/flexray.h> +#include <linux/flexray/core.h> +#include <linux/flexray/raw.h> +#include <net/sock.h> +#include <net/net_namespace.h> + +#define MASK_ALL 0 + +struct flexray_raw_sock { + struct sock sk; + int bound; + int ifindex; + struct notifier_block notifier; + struct flexray_filter dfilter; /* default/single filter */ +}; + +static inline unsigned int *raw_flags(struct sk_buff *skb) +{ + BUILD_BUG_ON(sizeof(skb->cb) <= (sizeof(struct sockaddr_flexray) + + sizeof(unsigned int))); + + /* return pointer after struct sockaddr_flexray */ + return (unsigned int *)(&((struct sockaddr_flexray *)skb->cb)[1]); +} + +static inline struct flexray_raw_sock *raw_sk(const struct sock *sk) +{ + return (struct flexray_raw_sock *)sk; +} + +static void raw_rcv(struct sk_buff *oskb, void *data) +{ + struct sock *sk = (struct sock *)data; + struct sockaddr_flexray *addr; + struct sk_buff *skb; + unsigned int *pflags; + + /* check the received tx sock reference */ + if (oskb->sk == sk) + return; + + /* clone the given skb to be able to enqueue it into the rcv queue */ + skb = skb_clone(oskb, GFP_ATOMIC); + if (!skb) + return; + + /* Put the datagram to the queue so that raw_recvmsg() can + * get it from there. We need to pass the interface index to + * raw_recvmsg(). We pass a whole struct sockaddr_flexray in skb->cb + * containing the interface index. + */ + + BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct sockaddr_flexray)); + addr = (struct sockaddr_flexray *)skb->cb; + memset(addr, 0, sizeof(*addr)); + addr->flexray_family = AF_FLEXRAY; + addr->flexray_ifindex = skb->dev->ifindex; + + /* add FlexRay specific message flags for raw_recvmsg() */ + pflags = raw_flags(skb); + *pflags = 0; + if (oskb->sk) + *pflags |= MSG_DONTROUTE; + if (oskb->sk == sk) + *pflags |= MSG_CONFIRM; + + if (sock_queue_rcv_skb(sk, skb) < 0) + kfree_skb(skb); +} + +static int raw_enable_allfilters(struct net_device *dev, struct sock *sk) +{ + return flexray_rx_register(dev, raw_rcv, sk, "raw"); +} + +static inline void raw_disable_allfilters(struct net_device *dev, + struct sock *sk) +{ + flexray_rx_unregister(dev, raw_rcv, sk); +} + +static struct flexray_raw_sock *nb_to_raw_sock(struct notifier_block *nb) +{ + return container_of(nb, struct flexray_raw_sock, notifier); +} + +static int raw_notifier(struct notifier_block *nb, + unsigned long msg, void *data) +{ + struct net_device *dev = (struct net_device *)data; + struct flexray_raw_sock *ro = nb_to_raw_sock(nb); + struct sock *sk = &ro->sk; + + if (!net_eq(dev_net(dev), &init_net)) + return NOTIFY_DONE; + + if (dev->type != ARPHRD_FLEXRAY) + return NOTIFY_DONE; + + if (ro->ifindex != dev->ifindex) + return NOTIFY_DONE; + + switch (msg) { + + case NETDEV_UNREGISTER: + lock_sock(sk); + /* remove current filters & unregister */ + if (ro->bound) + raw_disable_allfilters(dev, sk); + + ro->ifindex = 0; + ro->bound = 0; + release_sock(sk); + + sk->sk_err = ENODEV; + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_error_report(sk); + break; + + case NETDEV_DOWN: + sk->sk_err = ENETDOWN; + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_error_report(sk); + break; + } + + return NOTIFY_DONE; +} + +static int raw_init(struct sock *sk) +{ + struct flexray_raw_sock *ro = raw_sk(sk); + + ro->bound = 0; + ro->ifindex = 0; + + /* set notifier */ + ro->notifier.notifier_call = raw_notifier; + + register_netdevice_notifier(&ro->notifier); + + return 0; +} + +static int raw_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + struct flexray_raw_sock *ro; + + if (!sk) + return 0; + + ro = raw_sk(sk); + + unregister_netdevice_notifier(&ro->notifier); + + lock_sock(sk); + + /* remove current filters & unregister */ + if (ro->bound) { + if (ro->ifindex) { + struct net_device *dev; + + dev = dev_get_by_index(&init_net, ro->ifindex); + if (dev) { + raw_disable_allfilters(dev, sk); + dev_put(dev); + } + } else + raw_disable_allfilters(NULL, sk); + } + + ro->ifindex = 0; + ro->bound = 0; + + sock_orphan(sk); + sock->sk = NULL; + + release_sock(sk); + sock_put(sk); + + return 0; +} + +static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len) +{ + struct sockaddr_flexray *addr = (struct sockaddr_flexray *)uaddr; + struct sock *sk = sock->sk; + struct flexray_raw_sock *ro = raw_sk(sk); + int ifindex; + int err = 0; + int notify_enetdown = 0; + + if (len < sizeof(*addr)) + return -EINVAL; + + lock_sock(sk); + + if (ro->bound && addr->flexray_ifindex == ro->ifindex) + goto out; + + if (addr->flexray_ifindex) { + struct net_device *dev; + + dev = dev_get_by_index(&init_net, addr->flexray_ifindex); + if (!dev) { + err = -ENODEV; + goto out; + } + + if (dev->type != ARPHRD_FLEXRAY) { + dev_put(dev); + err = -ENODEV; + goto out; + } + + if (!(dev->flags & IFF_UP)) + notify_enetdown = 1; + + ifindex = dev->ifindex; + + /* filters set by default/setsockopt */ + err = raw_enable_allfilters(dev, sk); + + dev_put(dev); + } else { + ifindex = 0; + + /* filters set by default/setsockopt */ + err = raw_enable_allfilters(NULL, sk); + } + + if (!err) { + if (ro->bound) { + /* unregister old filters */ + if (ro->ifindex) { + struct net_device *dev; + + dev = dev_get_by_index(&init_net, ro->ifindex); + if (dev) { + raw_disable_allfilters(dev, sk); + dev_put(dev); + } + } else + raw_disable_allfilters(NULL, sk); + } + + ro->ifindex = ifindex; + ro->bound = 1; + } + +out: + release_sock(sk); + + if (notify_enetdown) { + sk->sk_err = ENETDOWN; + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_error_report(sk); + } + + return err; +} + +static int raw_getname(struct socket *sock, struct sockaddr *uaddr, + int *len, int peer) +{ + struct sockaddr_flexray *addr = (struct sockaddr_flexray *)uaddr; + struct sock *sk = sock->sk; + struct flexray_raw_sock *ro = raw_sk(sk); + + if (peer) + return -EOPNOTSUPP; + + memset(addr, 0, sizeof(*addr)); + addr->flexray_family = AF_FLEXRAY; + addr->flexray_ifindex = ro->ifindex; + + *len = sizeof(*addr); + + return 0; +} + +static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t size) +{ + struct sock *sk = sock->sk; + struct flexray_raw_sock *ro = raw_sk(sk); + struct sk_buff *skb; + struct net_device *dev; + int ifindex; + int err; + + if (msg->msg_name) { + struct sockaddr_flexray *addr = + (struct sockaddr_flexray *)msg->msg_name; + + if (msg->msg_namelen < sizeof(*addr)) + return -EINVAL; + + if (addr->flexray_family != AF_FLEXRAY) + return -EINVAL; + + ifindex = addr->flexray_ifindex; + } else + ifindex = ro->ifindex; + + dev = dev_get_by_index(&init_net, ifindex); + if (!dev) + return -ENXIO; + + skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, + &err); + if (!skb) + goto put_dev; + + err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); + if (err < 0) + goto free_skb; + + sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags); + + skb->dev = dev; + skb->sk = sk; + + err = flexray_send(skb); + if (err) + goto put_dev; + + dev_put(dev); + + return size; + +free_skb: + kfree_skb(skb); +put_dev: + dev_put(dev); + + return err; +} + +static int raw_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t size, int flags) +{ + struct sock *sk = sock->sk; + struct sk_buff *skb; + int err = 0; + int noblock; + + noblock = flags & MSG_DONTWAIT; + flags &= ~MSG_DONTWAIT; + + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) + return err; + + if (size < skb->len) + msg->msg_flags |= MSG_TRUNC; + else + size = skb->len; + + err = memcpy_toiovec(msg->msg_iov, skb->data, size); + if (err < 0) { + skb_free_datagram(sk, skb); + return err; + } + + sock_recv_ts_and_drops(msg, sk, skb); + + if (msg->msg_name) { + msg->msg_namelen = sizeof(struct sockaddr_flexray); + memcpy(msg->msg_name, skb->cb, msg->msg_namelen); + } + + /* assign the flags that have been recorded in raw_rcv() */ + msg->msg_flags |= *(raw_flags(skb)); + + skb_free_datagram(sk, skb); + + return size; +} + +static const struct proto_ops raw_ops = { + .family = PF_FLEXRAY, + .release = raw_release, + .bind = raw_bind, + .connect = sock_no_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = raw_getname, + .poll = datagram_poll, + .ioctl = flexray_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .sendmsg = raw_sendmsg, + .recvmsg = raw_recvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +}; + +static struct proto raw_proto __read_mostly = { + .name = "FLEXRAY_RAW", + .owner = THIS_MODULE, + .obj_size = sizeof(struct flexray_raw_sock), + .init = raw_init, +}; + +static const struct flexray_proto raw_flexray_proto = { + .type = SOCK_RAW, + .protocol = FLEXRAY_RAW, + .ops = &raw_ops, + .prot = &raw_proto, +}; + +static __init int raw_module_init(void) +{ + int err; + + err = flexray_proto_register(&raw_flexray_proto); + if (err < 0) + pr_err("flexray: registration of raw protocol failed\n"); + + return err; +} +module_init(raw_module_init); + +static __exit void raw_module_exit(void) +{ + flexray_proto_unregister(&raw_flexray_proto); +} +module_exit(raw_module_exit); + +MODULE_DESCRIPTION("PF_FLEXRAY raw protocol"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Benedikt Spranger <b.spranger@...utronix.de>"); +MODULE_ALIAS("flexray-proto-1"); -- 1.8.4.rc2 -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists