From: Arkadiusz Kubalewski <arkadiusz.kubalew...@intel.com>

Add interface for sending and receiving ESMC frames.
Ethernet Synchronization Messaging Channel (ESMC) requires
to operate on multicast raw L2 socket. This patch adds features
to open socket, send and receive ESMC frames.

Co-developed-by: Anatolii Gerasymenko <anatolii.gerasyme...@intel.com>
Signed-off-by: Anatolii Gerasymenko <anatolii.gerasyme...@intel.com>
Co-developed-by: Michal Michalik <michal.micha...@intel.com>
Signed-off-by: Michal Michalik <michal.micha...@intel.com>
Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalew...@intel.com>

---
v4: changed order of patch in patch-series
v3: rebase patch series

 esmc_socket.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 esmc_socket.h | 42 +++++++++++++++++++++++++
 2 files changed, 141 insertions(+)
 create mode 100644 esmc_socket.c
 create mode 100644 esmc_socket.h

diff --git a/esmc_socket.c b/esmc_socket.c
new file mode 100644
index 0000000..a675d33
--- /dev/null
+++ b/esmc_socket.c
@@ -0,0 +1,99 @@
+/**
+ * @file esmc_socket.c
+ * @brief Implements the ESMC socket.
+ * @note SPDX-FileCopyrightText: Copyright 2022 Intel Corporation
+ * @note SPDX-License-Identifier: GPL-2.0+
+ */
+#include <errno.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <linux/if_ether.h>
+
+#include "sk.h"
+#include "print.h"
+#include "synce_msg.h"
+#include "synce_msg_private.h"
+#include "esmc_socket.h"
+
+int open_esmc_socket(const char *iface)
+{
+       unsigned char multicast_macaddr[MAC_LEN] = SYNCE_DEST_MACADDR;
+       struct sockaddr_ll addr;
+       struct packet_mreq mreq;
+       int fd, index, err;
+
+       fd = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 
htons(SYNCE_ETHERTYPE));
+       if (fd < 0) {
+               pr_err("socket failed: %m");
+               return -1;
+       }
+       index = sk_interface_index(fd, iface);
+       if (index < 0) {
+               goto no_option;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sll_ifindex = index;
+       addr.sll_family = AF_PACKET;
+       addr.sll_protocol = htons(SYNCE_ETHERTYPE);
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr))) {
+               pr_err("bind failed: %m");
+               goto no_option;
+       }
+       err = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, iface,
+                        strnlen(iface, IFNAMSIZ));
+       if (err) {
+               pr_err("setsockopt SO_BINDTODEVICE failed: %m");
+               goto no_option;
+       }
+
+       memset(&mreq, 0, sizeof(mreq));
+       mreq.mr_ifindex = index;
+       mreq.mr_type = PACKET_MR_MULTICAST;
+       mreq.mr_alen = MAC_LEN;
+       if (sizeof(mreq.mr_address) * sizeof(mreq.mr_address[0]) <
+           sizeof(multicast_macaddr) * sizeof(multicast_macaddr[0])) {
+               pr_err("setting multicast address failed");
+               goto no_option;
+       }
+       memset(mreq.mr_address, 0, sizeof(mreq.mr_address));
+       // we need to copy only 6 bytes to mreq.mr_address
+       memcpy(mreq.mr_address, multicast_macaddr, sizeof(multicast_macaddr));
+
+       err = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, 
sizeof(mreq));
+       if (err) {
+               pr_warning("setsockopt PACKET_MR_MULTICAST failed: %m");
+       }
+
+       return fd;
+
+no_option:
+       close(fd);
+
+       return -1;
+}
+
+int send_raw_esmc_frame(int socket, void *frame, int frame_len, int ifindex)
+{
+       struct sockaddr_ll saddrll;
+       int ret, frame_size;
+
+       memset(&saddrll, 0, sizeof(saddrll));
+       saddrll.sll_ifindex = ifindex;
+
+       frame_size = frame_len > ETH_ZLEN ? frame_len : ETH_ZLEN;
+       ret = sendto(socket, frame, frame_size, 0,
+                    (struct sockaddr *)&saddrll, sizeof(saddrll));
+       if (ret < 0) {
+               pr_err("%s failed: %m", __func__);
+               return errno;
+       }
+
+       return 0;
+}
+
+int recv_raw_esmc_frame(int socket, void *buff, size_t buff_len)
+{
+       return recv(socket, buff, buff_len, 0);
+}
diff --git a/esmc_socket.h b/esmc_socket.h
new file mode 100644
index 0000000..2a9c80f
--- /dev/null
+++ b/esmc_socket.h
@@ -0,0 +1,42 @@
+/**
+ * @file esmc_socket.h
+ * @brief Implements the ESMC socket.
+ * @note SPDX-FileCopyrightText: Copyright 2022 Intel Corporation
+ * @note SPDX-License-Identifier: GPL-2.0+
+ */
+#ifndef HAVE_ESMC_SOCKET_H
+#define HAVE_ESMC_SOCKET_H
+
+/**
+ * Creates a raw ESMC socket and binds it to given interface.
+ *
+ * This high level API creates raw socket and binds it to specified
+ * interface and binds it to ESMC L2 multicast address. Thanks to
+ * those binds we are able to receive frames only on specified interface.
+ *
+ * @param iface        A name of interface to bind to raw socket
+ * @return     A raw socket file descriptor, negative if error occurred
+ */
+int open_esmc_socket(const char *iface);
+
+/**
+ * Sends a raw ESMC frame on given interface.
+ *
+ * @param socket               A file descriptor of open raw ESMC socket
+ * @param frame                A pointer to raw ESMC frame buffer
+ * @param frame_len    A size of frame to be sent
+ * @return             Zero on success, non-zero if the sending failed
+ */
+int send_raw_esmc_frame(int socket, void *frame, int frame_len, int ifindex);
+
+/**
+ * Receives a raw ESMC frame on given interface.
+ *
+ * @param socket               A file descriptor of open raw ESMC socket
+ * @param buff         A pointer to raw ESMC frame buffer
+ * @param buff_len     A buffer size - maximum data to recv
+ * @return             Zero on success, non-zero if the reception failed
+ */
+int recv_raw_esmc_frame(int socket, void *buff, size_t buff_len);
+
+#endif
-- 
2.9.5



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to