From eb387c901276ee61f409e0a1de1f4e21aa1d7a12 Mon Sep 17 00:00:00 2001 From: invincibler Date: Mon, 28 Oct 2024 05:30:54 +0000 Subject: [PATCH] #IAY93W six documents on network components were added #IAY93W six documents on network components were added Signed-off-by: invincibler --- dcb.rst | 107 +++++++++++++++++++++++++++ iucv.rst | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++++ l3mdev.rst | 118 +++++++++++++++++++++++++++++ nsh.rst | 142 +++++++++++++++++++++++++++++++++++ psample.rst | 71 ++++++++++++++++++ rfkill.rst | 198 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 845 insertions(+) create mode 100644 dcb.rst create mode 100644 iucv.rst create mode 100644 l3mdev.rst create mode 100644 nsh.rst create mode 100644 psample.rst create mode 100644 rfkill.rst diff --git a/dcb.rst b/dcb.rst new file mode 100644 index 00000000..41d2b057 --- /dev/null +++ b/dcb.rst @@ -0,0 +1,107 @@ +.. DCB +======= + +Overview +-------- + +The `dcb` module implements support for Data Center Bridging (DCB), which is a set of Ethernet enhancements that allow different types of network traffic with varying requirements (such as high reliability, no packet loss, and low latency) to coexist on the same Ethernet link. The main features of DCB include: + +- **Enhanced Transmission Selection (ETS)**: Provides a framework for assigning bandwidth guarantees to traffic classes. +- **Priority-based Flow Control (PFC)**: Offers flow control mechanisms that can work independently for each 802.1p priority. +- **Congestion Notification**: Provides end-to-end congestion control for protocols without built-in congestion management. + +Key Files +--------- + +- **dcbevent.c**: Manages event notifications related to DCB. +- **dcbnl.c**: Implements the rtnetlink interface for configuring DCB features. + +Function Descriptions +--------------------- + +### dcbevent.c + +**Function Description** +The `dcbevent.c` file contains functions for managing event notifications related to DCB, allowing other kernel components to be notified of changes or events. + +.. code-block:: c + + int register_dcbevent_notifier(struct notifier_block *nb) + { + return atomic_notifier_chain_register(&dcbevent_notif_chain, nb); + } + + int unregister_dcbevent_notifier(struct notifier_block *nb) + { + return atomic_notifier_chain_unregister(&dcbevent_notif_chain, nb); + } + + int call_dcbevent_notifiers(unsigned long val, void *v) + { + return atomic_notifier_call_chain(&dcbevent_notif_chain, val, v); + } + +**Open Capabilities** +- **Custom Notifier Registration**: Developers can create their own `notifier_block` structures and use `register_dcbevent_notifier` to receive notifications about DCB-related events. +- **Event Handling**: By implementing the `notifier_call` function within the `notifier_block`, developers can define custom behavior in response to DCB events. + +### dcbnl.c + +**Function Description** +The `dcbnl.c` file provides the rtnetlink interface for configuring DCB features, including setting and getting parameters for ETS, PFC, and application priorities. + +.. code-block:: c + + static int dcbnl_getstate(struct net_device *netdev, struct nlmsghdr *nlh, + u32 seq, struct nlattr **tb, struct sk_buff *skb) + { + if (!netdev->dcbnl_ops->getstate) + return -EOPNOTSUPP; + return nla_put_u8(skb, DCB_ATTR_STATE, netdev->dcbnl_ops->getstate(netdev)); + } + + static int dcbnl_getpfccfg(struct net_device *netdev, struct nlmsghdr *nlh, + u32 seq, struct nlattr **tb, struct sk_buff *skb) + { + struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest; + u8 value; + int ret; + int i; + int getall = 0; + + if (!tb[DCB_ATTR_PFC_CFG]) + return -EINVAL; + if (!netdev->dcbnl_ops->getpfccfg) + return -EOPNOTSUPP; + ret = nla_parse_nested_deprecated(data, DCB_PFC_UP_ATTR_MAX, + tb[DCB_ATTR_PFC_CFG], + dcbnl_pfc_up_nest, NULL); + if (ret) + return ret; + + nest = nla_nest_start_noflag(skb, DCB_ATTR_PFC_CFG); + if (!nest) + return -EMSGSIZE; + + if (data[DCB_PFC_UP_ATTR_ALL]) + getall = 1; + + for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { + if (!getall && !data[i]) + continue; + netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value); + ret = nla_put_u8(skb, i, value); + if (ret) + //Part of the source code is omitted here + } + +**Open Capabilities** +- **Configuration Access**: Developers can access and modify the DCB configuration of network devices through the provided rtnetlink operations. +- **Custom Feature Support**: By extending the `dcbnl_ops` structure, developers can add support for additional DCB features or customize existing ones. + +Open Capabilities +----------------- + +- **Notification System Extension**: Developers can extend the notification system by adding new notifiers to handle specific events. +- **rtnetlink Interface Customization**: Through the rtnetlink API, developers can implement custom logic to interact with the DCB settings of network interfaces, such as retrieving or updating configurations. +- **Device-Specific Enhancements**: By modifying or extending the `dcbnl_ops` structure, developers can tailor the DCB functionality to better fit the needs of specific network hardware. \ No newline at end of file diff --git a/iucv.rst b/iucv.rst new file mode 100644 index 00000000..7b2b9af3 --- /dev/null +++ b/iucv.rst @@ -0,0 +1,209 @@ +IUCV +===== + +af_iucv.c (AF_IUCV Sockets) +--------------------------- + +**Function Description** +The `af_iucv.c` file implements the socket layer interface for the IUCV protocol stack, allowing user-space programs to use IUCV for communication. It includes key functions such as creating and destroying sockets, binding addresses, listening for connection requests, and handling data transmission. + +.. code-block:: c + :linenos: + + static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio, int kern) { + struct sock *sk; + struct iucv_sock *iucv; + sk = sk_alloc(&init_net, PF_IUCV, prio, &iucv_proto, kern); + if (!sk) + return NULL; + iucv = iucv_sk(sk); + sock_init_data(sock, sk); + INIT_LIST_HEAD(&iucv->accept_q); + spin_lock_init(&iucv->accept_q_lock); + skb_queue_head_init(&iucv->send_skb_q); + INIT_LIST_HEAD(&iucv->message_q.list); + spin_lock_init(&iucv->message_q.lock); + skb_queue_head_init(&iucv->backlog_skb_q); + iucv->send_tag = 0; + atomic_set(&iucv->pendings, 0); + iucv->flags = 0; + iucv->msglimit = 0; + atomic_set(&iucv->msg_sent, 0); + atomic_set(&iucv->msg_recv, 0); + iucv->path = NULL; + iucv->sk_txnotify = afiucv_hs_callback_txnotify; + memset(&iucv->src_user_id, 0, 32); + if (pr_iucv) + iucv->transport = AF_IUCV_TRANS_IUCV; + else + iucv->transport = AF_IUCV_TRANS_HIPER; + sk->sk_destruct = iucv_sock_destruct; + sk->sk_sndtimeo = IUCV_CONN_TIMEOUT; + sock_reset_flag(sk, SOCK_ZAPPED); + sk->sk_protocol = proto; + sk->sk_state = IUCV_OPEN; + iucv_sock_link(&iucv_sk_list, sk); + return sk; + } + + static void iucv_accept_enqueue(struct sock *parent, struct sock *sk) { + unsigned long flags; + struct iucv_sock *par = iucv_sk(parent); + sock_hold(sk); + spin_lock_irqsave(&par->accept_q_lock, flags); + list_add_tail(&iucv_sk(sk)->accept_q, &par->accept_q); + spin_unlock_irqrestore(&par->accept_q_lock, flags); + iucv_sk(sk)->parent = parent; + sk_acceptq_added(parent); + } + + static int iucv_callback_connreq(struct iucv_path *path, u8 ipvmid[8], u8 ipuser[16]) { + unsigned char user_data[16]; + unsigned char nuser_data[16]; + unsigned char src_name[8]; + struct sock *sk, *nsk; + struct iucv_sock *iucv, *niucv; + int err; + memcpy(src_name, ipuser, 8); + EBCASC(src_name, 8); + read_lock(&iucv_sk_list.lock); + iucv = NULL; + sk = NULL; + sk_for_each(sk, &iucv_sk_list.head) + if (sk->sk_state == IUCV_LISTEN && + !memcmp(&iucv_sk(sk)->src_name, src_name, 8)) { + iucv = iucv_sk(sk); + break; + } + read_unlock(&iucv_sk_list.lock); + if (!iucv) + return -EINVAL; + bh_lock_sock(sk); + low_nmcpy(user_data, iucv->src_name); + high_nmcpy(user_data, iucv->dst_name); + ASCEBC(user_data, sizeof(user_data)); + if (sk->sk_state != IUCV_LISTEN) { + err = pr_iucv->path_sever(path, user_data); + iucv_path_free(path); + goto fail; + } + if (sk_acceptq_is_full(sk)) { + err = pr_iucv->path_sever(path, user_data); + iucv_path_free(path); + goto fail; + } + nsk = iucv_sock_alloc(NULL, sk->sk_protocol, GFP_ATOMIC, 0); + if (!nsk) { + err = pr_iucv->path_sever(path, user_data); + iucv_path_free(path); + goto fail; + } + niucv = iucv_sk(nsk); + iucv_sock_init(nsk, sk); + niucv->transport = AF_IUCV_TRANS_IUCV; + nsk->sk_allocation |= GFP_DMA; + memcpy(niucv->dst_name, ipuser + 8, 8); + EBCASC(niucv->dst_name, 8); + memcpy(niucv->dst_user_id, ipvmid, 8); + memcpy(niucv->src_name, iucv->src_name, 8); + memcpy(niucv->src_user_id, iucv->src_user_id, 8); + niucv->path = path; + high_nmcpy(nuser_data, ipuser + 8); + memcpy(nuser_data + 8, niucv->src_name, 8); + ASCEBC(nuser_data + 8, 8); + niucv->msglimit = iucv->msglimit; + path->msglim = iucv->msglimit; + err = pr_iucv->path_accept(path, &af_iucv_handler, nuser_data, nsk); + if (err) { + iucv_sever_path(nsk, 1); + iucv_sock_kill(nsk); + goto fail; + } + iucv_accept_enqueue(sk, nsk); + nsk->sk_state = IUCV_CONNECTED; + sk->sk_data_ready(sk); + err = 0; + fail: + release_sock(sk); + return err; + } + +**Open Capabilities** +- **Custom Socket Behavior**: Developers can extend or modify the socket allocation and initialization logic to support specific application scenarios. +- **Connection Management**: By overriding or extending existing callback functions, such as `iucv_callback_connreq`, developers can control how new connection requests are handled, enabling more advanced security and policy controls. +- **Data Flow Control**: When sending and receiving data, developers can optimize performance by adjusting socket parameters, such as setting message limits (`msglimit`). + +iucv.c (IUCV Base Infrastructure) +--------------------------------- + +**Function Description** +The `iucv.c` file provides the base infrastructure support for IUCV, including path management, interrupt handling, and the execution of underlying IUCV commands. + +.. code-block:: c + :linenos: + + static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg) { + struct sock *sk = path->private; + struct iucv_sock *iucv = iucv_sk(sk); + struct sk_buff *skb; + struct sock_msg_q *save_msg; + int len; + if (sk->sk_shutdown & RCV_SHUTDOWN) { + pr_iucv->message_reject(path, msg); + return; + } + spin_lock(&iucv->message_q.lock); + if (!list_empty(&iucv->message_q.list) || + !skb_queue_empty(&iucv->backlog_skb_q)) + goto save_message; + len = atomic_read(&sk->sk_rmem_alloc); + len += SKB_TRUESIZE(iucv_msg_length(msg)); + if (len > sk->sk_rcvbuf) + goto save_message; + skb = alloc_iucv_recv_skb(iucv_msg_length(msg)); + if (!skb) + goto save_message; + iucv_process_message(sk, skb, path, msg); + goto out_unlock; + save_message: + save_msg = kzalloc(sizeof(struct sock_msg_q), GFP_ATOMIC | GFP_DMA); + if (!save_msg) + goto out_unlock; + save_msg->path = path; + save_msg->msg = *msg; + list_add_tail(&save_msg->list, &iucv->message_q.list); + out_unlock: + spin_unlock(&iucv->message_q.lock); + } + + static void iucv_callback_txdone(struct iucv_path *path, struct iucv_message *msg) { + struct sock *sk = path->private; + struct sk_buff *this = NULL; + struct sk_buff_head *list = &iucv_sk(sk)->send_skb_q; + struct sk_buff *list_skb; + unsigned long flags; + bh_lock_sock(sk); + while ((list_skb = __skb_dequeue(list))) { + if (list_skb == this) { + kfree_skb(list_skb); + if (sk->sk_state == IUCV_CONNECTED) { + sk->sk_state = IUCV_DISCONN; + sk->sk_state_change(sk); + } + break; + } + break; + } + spin_unlock_irqrestore(&list->lock, flags); + if (sk->sk_state == IUCV_CLOSING) { + if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) { + sk->sk_state = IUCV_CLOSED; + sk->sk_state_change(sk); + } + } + } + +**Open Capabilities** +- **CPU Preparation and Cleanup**: Developers can customize the preparation and cleanup of CPUs during system startup or shutdown to accommodate special requirements. +- **Path Management**: By calling functions like `iucv_sever_path`, developers can manually manage IUCV paths, providing direct control over network topology. +- **Message Handling**: By implementing their own `iucv_callback_rx` and `iucv_callback_txdone` callbacks, developers can process received data packets and handle transmission completions according to application needs, enabling filtering, forwarding, or other business logic. \ No newline at end of file diff --git a/l3mdev.rst b/l3mdev.rst new file mode 100644 index 00000000..827e96c6 --- /dev/null +++ b/l3mdev.rst @@ -0,0 +1,118 @@ +l3mdev +================ + +l3mdev.c (L3 Master Device) +--------------------------- +**Function Description** + +The `l3mdev.c` file implements the L3 master device support, which allows the core networking code to interact with device drivers that manage L3 master devices like VRF. The following are key functions and their descriptions: + +.. code-block:: c + int l3mdev_table_lookup_register(enum l3mdev_type l3type, lookup_by_table_id_t fn) + { + struct l3mdev_handler *hdlr; + int res; + + res = l3mdev_check_type(l3type); + if (res) + return res; + hdlr = &l3mdev_handlers[l3type]; + spin_lock(&l3mdev_lock); + if (hdlr->dev_lookup) { + res = -EBUSY; + goto unlock; + } + hdlr->dev_lookup = fn; + res = 0; + unlock: + spin_unlock(&l3mdev_lock); + return res; + } + +- **Function Explanation**: This function registers a lookup function based on the table ID. It first checks if the L3 device type is valid, then locks the spinlock to protect the data structure. If a lookup function for the given type already exists, it returns `-EBUSY`. Otherwise, it stores the provided function pointer and unlocks the spinlock. +- **Open Capabilities**: Developers can register their own lookup functions to extend the L3 device lookup logic. + +.. code-block:: c + void l3mdev_table_lookup_unregister(enum l3mdev_type l3type, lookup_by_table_id_t fn) + { + struct l3mdev_handler *hdlr; + + if (l3mdev_check_type(l3type)) + return; + hdlr = &l3mdev_handlers[l3type]; + spin_lock(&l3mdev_lock); + if (hdlr->dev_lookup == fn) + hdlr->dev_lookup = NULL; + spin_unlock(&l3mdev_lock); + } + +- **Function Explanation**: This function unregisters a lookup function based on the table ID. It checks the L3 device type, locks the spinlock, and if the stored function pointer matches the provided one, it sets it to `NULL` and unlocks the spinlock. +- **Open Capabilities**: Developers can unregister previously registered lookup functions to clean up resources or change the lookup logic. + +.. code-block:: c + int l3mdev_ifindex_lookup_by_table_id(enum l3mdev_type l3type, struct net *net, u32 table_id) + { + lookup_by_table_id_t lookup; + struct l3mdev_handler *hdlr; + int ifindex = -EINVAL; + int res; + + res = l3mdev_check_type(l3type); + if (res) + return res; + hdlr = &l3mdev_handlers[l3type]; + spin_lock(&l3mdev_lock); + lookup = hdlr->dev_lookup; + if (!lookup) + goto unlock; + ifindex = lookup(net, table_id); + unlock: + spin_unlock(&l3mdev_lock); + return ifindex; + } + +- **Function Explanation**: This function looks up the device index based on the L3 device type, network namespace, and table ID. It checks the L3 device type, locks the spinlock, and if a lookup function is found, it calls the function and returns the result. If no lookup function is found, it returns `-EINVAL`. +- **Open Capabilities**: Developers can use this function to look up the device index for different L3 device types and table IDs. + +.. code-block:: c + int l3mdev_master_ifindex_rcu(const struct net_device *dev) + { + int ifindex = 0; + if (!dev) + return 0; + if (netif_is_l3_master(dev)) { + ifindex = dev->ifindex; + } else if (netif_is_l3_slave(dev)) { + struct net_device *master; + struct net_device *_dev = (struct net_device *)dev; + master = netdev_master_upper_dev_get_rcu(_dev); + if (master) + ifindex = master->ifindex; + } + return ifindex; + } + +- **Function Explanation**: This function gets the index of the L3 master device. If the device is an L3 master, it returns its index. If the device is an L3 slave, it finds its master and returns the master's index. +- **Open Capabilities**: Developers can determine if a device is an L3 master or slave and get the index of the master device. + +.. code-block:: c + u32 l3mdev_fib_table_rcu(const struct net_device *dev) + { + u32 tb_id = 0; + if (!dev) + return 0; + if (netif_is_l3_master(dev)) { + if (dev->l3mdev_ops->l3mdev_fib_table) + tb_id = dev->l3mdev_ops->l3mdev_fib_table(dev); + } else if (netif_is_l3_slave(dev)) { + struct net_device *_dev = (struct net_device *) dev; + const struct net_device *master; + master = netdev_master_upper_dev_get_rcu(_dev); + if (master && master->l3mdev_ops->l3mdev_fib_table) + tb_id = master->l3mdev_ops->l3mdev_fib_table(master); + } + return tb_id; + } + +- **Function Explanation**: This function retrieves the FIB table ID associated with the L3 master interface. If the device is an L3 master and has a defined `l3mdev_fib_table` function, it calls the function to get the FIB table ID. If the device is a slave, it finds its master and performs the same operation. +- **Open Capabilities**: Developers can query the FIB table associated with the L3 master interface, potentially influencing routing decisions. \ No newline at end of file diff --git a/nsh.rst b/nsh.rst new file mode 100644 index 00000000..3e9a1b19 --- /dev/null +++ b/nsh.rst @@ -0,0 +1,142 @@ +nsh +==== + +nsh.c (Network Service Header) +------------------------------ + +**Function Description** + +The `nsh.c` file implements the Network Service Header (NSH) protocol, which is part of the Service Function Chaining (SFC) framework. The file includes functions for adding and removing NSH headers and handling Generic Segmentation Offload (GSO) for NSH packets. + +.. code-block:: c + :caption: nsh_push function + + int nsh_push(struct sk_buff *skb, const struct nshhdr *pushed_nh) + { + struct nshhdr *nh; + size_t length = nsh_hdr_len(pushed_nh); + u8 next_proto; + if (skb->mac_len) { + next_proto = TUN_P_ETHERNET; + } else { + next_proto = tun_p_from_eth_p(skb->protocol); + if (!next_proto) + return -EAFNOSUPPORT; + } + if (skb_cow_head(skb, length) < 0) + return -ENOMEM; + skb_push(skb, length); + nh = (struct nshhdr *)(skb->data); + memcpy(nh, pushed_nh, length); + nh->np = next_proto; + skb_postpush_rcsum(skb, nh, length); + skb->protocol = htons(ETH_P_NSH); + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_mac_len(skb); + return 0; + } + +- **`nsh_push` function**: This function is responsible for adding an NSH header to the packet. + - It calculates the length of the NSH header to be added. + - Determines the next protocol type based on whether there is a MAC layer length. + - Ensures there is enough space to insert the NSH header using `skb_cow_head`. + - Copies the NSH header information into the packet and updates the relevant protocol fields and pointers. + - Sets the packet's protocol field to `ETH_P_NSH` and resets the MAC and network header pointers. + +.. code-block:: c + :caption: nsh_pop function + + int nsh_pop(struct sk_buff *skb) + { + struct nshhdr *nh; + size_t length; + __be16 inner_proto; + if (!pskb_may_pull(skb, NSH_BASE_HDR_LEN)) + return -ENOMEM; + nh = (struct nshhdr *)(skb->data); + length = nsh_hdr_len(nh); + if (length < NSH_BASE_HDR_LEN) + return -EINVAL; + inner_proto = tun_p_to_eth_p(nh->np); + if (!pskb_may_pull(skb, length)) + return -ENOMEM; + if (!inner_proto) + return -EAFNOSUPPORT; + skb_pull_rcsum(skb, length); + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_mac_len(skb); + skb->protocol = inner_proto; + return 0; + } + +- **`nsh_pop` function**: This function removes the NSH header from the packet. + - Verifies that the packet contains the complete NSH base header length. + - Calculates the total length of the NSH header. + - Checks if the NSH header length is valid. + - Retrieves the inner protocol type and verifies its validity. + - Removes the NSH header and restores the original state of the packet, including updating the protocol field and other related pointers. + +.. code-block:: c + :caption: nsh_gso_segment function + + static struct sk_buff *nsh_gso_segment(struct sk_buff *skb, netdev_features_t features) + { + unsigned int outer_hlen, mac_len, nsh_len; + struct sk_buff *segs = ERR_PTR(-EINVAL); + u16 mac_offset = skb->mac_header; + __be16 outer_proto, proto; + skb_reset_network_header(skb); + outer_proto = skb->protocol; + outer_hlen = skb_mac_header_len(skb); + mac_len = skb->mac_len; + if (unlikely(!pskb_may_pull(skb, NSH_BASE_HDR_LEN))) + goto out; + nsh_len = nsh_hdr_len(nsh_hdr(skb)); + if (nsh_len < NSH_BASE_HDR_LEN) + goto out; + if (unlikely(!pskb_may_pull(skb, nsh_len))) + goto out; + proto = tun_p_to_eth_p(nsh_hdr(skb)->np); + if (!proto) + goto out; + __skb_pull(skb, nsh_len); + skb_reset_mac_header(skb); + skb->mac_len = proto == htons(ETH_P_TEB) ? ETH_HLEN : 0; + skb->protocol = proto; + features &= NETIF_F_SG; + segs = skb_mac_gso_segment(skb, features); + if (IS_ERR_OR_NULL(segs)) { + skb_gso_error_unwind(skb, htons(ETH_P_NSH), nsh_len, + mac_offset, mac_len); + goto out; + } + for (skb = segs; skb; skb = skb->next) { + skb->protocol = outer_proto; + __skb_push(skb, nsh_len + outer_hlen); + skb_reset_mac_header(skb); + skb_set_network_header(skb, outer_hlen); + skb->mac_len = mac_len; + } + out: + return segs; + } + +- **`nsh_gso_segment` function**: This function handles GSO segmentation for NSH packets. + - Resets the network header pointer. + - Retrieves the outer protocol type and related lengths. + - Checks if there is enough data to contain the complete NSH base header. + - Calculates the total length of the NSH header and verifies its validity. + - Retrieves the inner protocol type and verifies its validity. + - Removes the NSH header and updates the packet's relevant information. + - Calls `skb_mac_gso_segment` to perform GSO segmentation. + - If segmentation fails, it unwinds the operation. + - Restores the NSH header and related pointers for each segment. + +**Open Capabilities** + +- **Custom Header Creation**: Developers can extend the `nsh_push` and `nsh_pop` functions to customize the construction and parsing logic of the NSH header. +- **GSO Segmentation Control**: By implementing or modifying the `nsh_gso_segment` function, developers can adjust the GSO segmentation behavior for NSH packets as needed. +- **Error Handling**: In the `nsh_push` and `nsh_pop` functions, developers can customize error handling logic, such as returning specific error codes or taking other actions. +- **Module Initialization Configuration**: In the `nsh_init_module` function, developers can customize the initial setup of the NSH module, such as registering offload handlers. \ No newline at end of file diff --git a/psample.rst b/psample.rst new file mode 100644 index 00000000..07e9f738 --- /dev/null +++ b/psample.rst @@ -0,0 +1,71 @@ +psample +=========== + +### psample.c (Packet Sampling) +------------------------------- + +**Function Description** +The `psample.c` file implements a Netlink channel for packet sampling, which allows transferring packets alongside some metadata to userspace. It includes group management and data transmission logic. + +.. code-block:: c + + static int psample_group_nl_fill(struct sk_buff *msg, + struct psample_group *group, + enum psample_command cmd, + u32 portid, u32 seq, int flags) + { + void *hdr; + int ret; + hdr = genlmsg_put(msg, portid, seq, &psample_nl_family, flags, cmd); + if (!hdr) + return -EMSGSIZE; + ret = nla_put_u32(msg, PSAMPLE_ATTR_SAMPLE_GROUP, group->group_num); + if (ret < 0) + goto error; + ret = nla_put_u32(msg, PSAMPLE_ATTR_GROUP_REFCOUNT, group->refcount); + if (ret < 0) + goto error; + ret = nla_put_u32(msg, PSAMPLE_ATTR_GROUP_SEQ, group->seq); + if (ret < 0) + goto error; + genlmsg_end(msg, hdr); + return 0; + error: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; + } + +This function fills a Netlink message with information about a specific sample group and sends it to userspace. It uses `genlmsg_put` and `nla_put_u32` to construct and add necessary attributes. + +.. code-block:: c + + void psample_sample_packet(struct psample_group *group, struct sk_buff *skb, + u32 trunc_size, int in_ifindex, int out_ifindex, + u32 sample_rate) + { + data_len = min(skb->len, trunc_size); + if (meta_len + nla_total_size(data_len) > PSAMPLE_MAX_PACKET_SIZE) + data_len = PSAMPLE_MAX_PACKET_SIZE - meta_len - NLA_HDRLEN - NLA_ALIGNTO; + + nl_skb = genlmsg_new(meta_len + nla_total_size(data_len), GFP_ATOMIC); + if (unlikely(!nl_skb)) + return; + data = genlmsg_put(nl_skb, 0, 0, &psample_nl_family, 0, PSAMPLE_CMD_SAMPLE); + if (unlikely(!data)) + goto error; + genlmsg_multicast_netns(&psample_nl_family, group->net, nl_skb, 0, + PSAMPLE_NL_MCGRP_SAMPLE, GFP_ATOMIC); + return; + error: + pr_err_ratelimited("Could not create psample log message\n"); + nlmsg_free(nl_skb); + } + +The `psample_sample_packet` function creates a new Netlink message containing the truncated packet data and associated metadata, and multicasts it to all user-space processes listening to the sample group. + +**Open Capabilities** +- **Custom Message Filling**: Developers can extend the `psample_group_nl_fill` function to customize the message content sent to userspace. +- **Sample Packet Handling**: The `psample_sample_packet` function allows developers to customize how sample packets and their metadata are handled. +- **Group Management**: Functions such as `psample_group_create`, `psample_group_destroy`, and `psample_group_lookup` provide the ability to create, destroy, and look up sample groups. +- **State Notification**: The `psample_group_notify` function can be used to notify userspace when the state of a sample group changes. +- **Query Interface**: The `psample_nl_cmd_get_group_dumpit` function provides an interface for querying all existing sample groups and their states. \ No newline at end of file diff --git a/rfkill.rst b/rfkill.rst new file mode 100644 index 00000000..1901a232 --- /dev/null +++ b/rfkill.rst @@ -0,0 +1,198 @@ +rfkill +=========== + +core.c (RF Switch Core) +----------------------- +**Function Description** +The `core.c` file implements the core functionalities for the RF switch subsystem, including state management and event handling for RF switches. It defines the `struct rfkill` and related operations. + +.. code-block:: c + + struct rfkill { + spinlock_t lock; + enum rfkill_type type; + unsigned long state; + u32 idx; + bool registered; + bool persistent; + bool polling_paused; + bool suspended; + const struct rfkill_ops *ops; + void *data; + #ifdef CONFIG_RFKILL_LEDS + struct led_trigger led_trigger; + const char *ledtrigname; + #endif + struct device dev; + struct list_head node; + struct delayed_work poll_work; + struct work_struct uevent_work; + struct work_struct sync_work; + char name[]; + }; + +- **State Management**: Manages the hardware and software states of RF switches. +- **Event Handling**: Handles events such as changes in the state of RF switches and triggers appropriate actions. + +**Open Capabilities** +- **Custom State Management**: Developers can extend the state management by implementing their own `rfkill_ops` structure, which includes functions like `poll`, `set_block`, and `query`. +- **Device Registration**: Through the `rfkill_register` function, developers can register their own RF switch devices with the system. +- **LED Trigger Support**: If LED support is enabled, developers can customize the behavior of LEDs using the `led_trigger` structure. + +.. code-block:: c + + int __must_check rfkill_register(struct rfkill *rfkill) { + } + + void rfkill_unregister(struct rfkill *rfkill) { + } + + void rfkill_destroy(struct rfkill *rfkill) { + } + +Kconfig (Configuration) +----------------------- +**Function Description** +The `Kconfig` file allows users to configure the RF switch subsystem via the kernel configuration tool. It enables or disables the subsystem and its optional features, such as LED trigger support and input handling. + +.. code-block:: none + + menuconfig RFKILL + tristate "RF switch subsystem support" + help + Say Y here if you want to have control over RF switches found on many WiFi and Bluetooth cards. + +**Open Capabilities** +- **Configurable Subsystem**: Users can enable or disable the RF switch subsystem and its features, allowing for flexibility in kernel configurations. + +rfkill.h (Header File) +---------------------- +**Function Description** +The `rfkill.h` header file defines the API for the RF switch subsystem, including functions for global switch operations, emergency power-off, and state restoration. + +.. code-block:: c + + void rfkill_switch_all(const enum rfkill_type type, bool blocked); + void rfkill_epo(void); + void rfkill_restore_states(void); + +**Open Capabilities** +- **API Access**: Developers can use the provided API to control all RF switches, perform an emergency power-off, and restore states, allowing for high-level control over the subsystem. + +rfkill-gpio.c (GPIO RF Kill Driver) +----------------------------------- +**Function Description** +The `rfkill-gpio.c` file provides a generic GPIO-based RF kill driver. It handles the initialization, probing, and removal of GPIO-based RF switches. + +.. code-block:: c + + static int rfkill_gpio_probe(struct platform_device *pdev) { + struct rfkill_gpio_data *rfkill; + struct gpio_desc *gpio; + const char *type_name; + int ret; + + rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL); + if (!rfkill) + return -ENOMEM; + + device_property_read_string(&pdev->dev, "name", &rfkill->name); + device_property_read_string(&pdev->dev, "type", &type_name); + if (!rfkill->name) + rfkill->name = dev_name(&pdev->dev); + + rfkill->type = rfkill_find_type(type_name); + if (ACPI_HANDLE(&pdev->dev)) { + ret = rfkill_gpio_acpi_probe(&pdev->dev, rfkill); + if (ret) + return ret; + } + + rfkill->clk = devm_clk_get(&pdev->dev, NULL); + gpio = devm_gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + rfkill->reset_gpio = gpio; + + gpio = devm_gpiod_get_optional(&pdev->dev, "shutdown", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + rfkill->shutdown_gpio = gpio; + + if (!rfkill->reset_gpio && !rfkill->shutdown_gpio) { + dev_err(&pdev->dev, "invalid platform data\n"); + return -EINVAL; + } + + rfkill->rfkill_dev = rfkill_alloc(rfkill->name, &pdev->dev, + rfkill->type, &rfkill_gpio_ops, + rfkill); + if (!rfkill->rfkill_dev) + return -ENOMEM; + + ret = rfkill_register(rfkill->rfkill_dev); + if (ret < 0) + goto err_destroy; + + platform_set_drvdata(pdev, rfkill); + dev_info(&pdev->dev, "%s device registered.\n", rfkill->name); + return 0; + + err_destroy: + rfkill_destroy(rfkill->rfkill_dev); + return ret; + } + + static int rfkill_gpio_remove(struct platform_device *pdev) { + struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev); + rfkill_unregister(rfkill->rfkill_dev); + rfkill_destroy(rfkill->rfkill_dev); + return 0; + } + +**Open Capabilities** +- **GPIO Customization**: Developers can customize the GPIO-based RF switch driver to work with specific hardware, including setting up GPIOs and handling probe and remove operations. +- **Platform Device Support**: The driver integrates with the platform device framework, making it easy to add support for new hardware. + +input.c (Input Layer Interface) +------------------------------- +**Function Description** +The `input.c` file provides an interface between the RF switch subsystem and the input layer. It handles input events and translates them into RF switch commands. + +.. code-block:: c + + static struct input_handler rfkill_handler = { + .name = "rfkill", + .event = rfkill_event, + .connect = rfkill_connect, + .start = rfkill_start, + .disconnect = rfkill_disconnect, + .id_table = rfkill_ids, + }; + + static void rfkill_event(struct input_handle *handle, unsigned int type, + unsigned int code, int data) { + if (type == EV_KEY && data == 1) { + switch (code) { + case KEY_WLAN: + rfkill_schedule_toggle(RFKILL_TYPE_WLAN); + break; + case KEY_BLUETOOTH: + rfkill_schedule_toggle(RFKILL_TYPE_BLUETOOTH); + break; + case KEY_UWB: + rfkill_schedule_toggle(RFKILL_TYPE_UWB); + break; + case KEY_WIMAX: + rfkill_schedule_toggle(RFKILL_TYPE_WIMAX); + break; + case KEY_RFKILL: + rfkill_schedule_toggle(RFKILL_TYPE_ALL); + break; + } + } else if (type == EV_SW && code == SW_RFKILL_ALL) + rfkill_schedule_evsw_rfkillall(data); + } + +**Open Capabilities** +- **Input Event Handling**: Developers can extend the input handler to handle custom input events and translate them into RF switch commands, providing a flexible way to interact with the RF switch subsystem. \ No newline at end of file -- Gitee