cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mpoa_proc.c (7353B)


      1// SPDX-License-Identifier: GPL-2.0
      2#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
      3
      4#ifdef CONFIG_PROC_FS
      5#include <linux/errno.h>
      6#include <linux/kernel.h>
      7#include <linux/string.h>
      8#include <linux/mm.h>
      9#include <linux/module.h>
     10#include <linux/proc_fs.h>
     11#include <linux/ktime.h>
     12#include <linux/seq_file.h>
     13#include <linux/uaccess.h>
     14#include <linux/atmmpc.h>
     15#include <linux/atm.h>
     16#include <linux/gfp.h>
     17#include "mpc.h"
     18#include "mpoa_caches.h"
     19
     20/*
     21 * mpoa_proc.c: Implementation MPOA client's proc
     22 * file system statistics
     23 */
     24
     25#if 1
     26#define dprintk(format, args...)					\
     27	printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args)  /* debug */
     28#else
     29#define dprintk(format, args...)					\
     30	do { if (0)							\
     31		printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
     32	} while (0)
     33#endif
     34
     35#if 0
     36#define ddprintk(format, args...)					\
     37	printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args)  /* debug */
     38#else
     39#define ddprintk(format, args...)					\
     40	do { if (0)							\
     41		printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
     42	} while (0)
     43#endif
     44
     45#define STAT_FILE_NAME "mpc"     /* Our statistic file's name */
     46
     47extern struct mpoa_client *mpcs;
     48extern struct proc_dir_entry *atm_proc_root;  /* from proc.c. */
     49
     50static int proc_mpc_open(struct inode *inode, struct file *file);
     51static ssize_t proc_mpc_write(struct file *file, const char __user *buff,
     52			      size_t nbytes, loff_t *ppos);
     53
     54static int parse_qos(const char *buff);
     55
     56static const struct proc_ops mpc_proc_ops = {
     57	.proc_open	= proc_mpc_open,
     58	.proc_read	= seq_read,
     59	.proc_lseek	= seq_lseek,
     60	.proc_write	= proc_mpc_write,
     61	.proc_release	= seq_release,
     62};
     63
     64/*
     65 * Returns the state of an ingress cache entry as a string
     66 */
     67static const char *ingress_state_string(int state)
     68{
     69	switch (state) {
     70	case INGRESS_RESOLVING:
     71		return "resolving  ";
     72	case INGRESS_RESOLVED:
     73		return "resolved   ";
     74	case INGRESS_INVALID:
     75		return "invalid    ";
     76	case INGRESS_REFRESHING:
     77		return "refreshing ";
     78	}
     79
     80	return "";
     81}
     82
     83/*
     84 * Returns the state of an egress cache entry as a string
     85 */
     86static const char *egress_state_string(int state)
     87{
     88	switch (state) {
     89	case EGRESS_RESOLVED:
     90		return "resolved   ";
     91	case EGRESS_PURGE:
     92		return "purge      ";
     93	case EGRESS_INVALID:
     94		return "invalid    ";
     95	}
     96
     97	return "";
     98}
     99
    100/*
    101 * FIXME: mpcs (and per-mpc lists) have no locking whatsoever.
    102 */
    103
    104static void *mpc_start(struct seq_file *m, loff_t *pos)
    105{
    106	loff_t l = *pos;
    107	struct mpoa_client *mpc;
    108
    109	if (!l--)
    110		return SEQ_START_TOKEN;
    111	for (mpc = mpcs; mpc; mpc = mpc->next)
    112		if (!l--)
    113			return mpc;
    114	return NULL;
    115}
    116
    117static void *mpc_next(struct seq_file *m, void *v, loff_t *pos)
    118{
    119	struct mpoa_client *p = v;
    120	(*pos)++;
    121	return v == SEQ_START_TOKEN ? mpcs : p->next;
    122}
    123
    124static void mpc_stop(struct seq_file *m, void *v)
    125{
    126}
    127
    128/*
    129 * READING function - called when the /proc/atm/mpoa file is read from.
    130 */
    131static int mpc_show(struct seq_file *m, void *v)
    132{
    133	struct mpoa_client *mpc = v;
    134	int i;
    135	in_cache_entry *in_entry;
    136	eg_cache_entry *eg_entry;
    137	time64_t now;
    138	unsigned char ip_string[16];
    139
    140	if (v == SEQ_START_TOKEN) {
    141		atm_mpoa_disp_qos(m);
    142		return 0;
    143	}
    144
    145	seq_printf(m, "\nInterface %d:\n\n", mpc->dev_num);
    146	seq_printf(m, "Ingress Entries:\nIP address      State      Holding time  Packets fwded  VPI  VCI\n");
    147	now = ktime_get_seconds();
    148
    149	for (in_entry = mpc->in_cache; in_entry; in_entry = in_entry->next) {
    150		unsigned long seconds_delta = now - in_entry->time;
    151
    152		sprintf(ip_string, "%pI4", &in_entry->ctrl_info.in_dst_ip);
    153		seq_printf(m, "%-16s%s%-14lu%-12u",
    154			   ip_string,
    155			   ingress_state_string(in_entry->entry_state),
    156			   in_entry->ctrl_info.holding_time -
    157			   seconds_delta,
    158			   in_entry->packets_fwded);
    159		if (in_entry->shortcut)
    160			seq_printf(m, "   %-3d  %-3d",
    161				   in_entry->shortcut->vpi,
    162				   in_entry->shortcut->vci);
    163		seq_printf(m, "\n");
    164	}
    165
    166	seq_printf(m, "\n");
    167	seq_printf(m, "Egress Entries:\nIngress MPC ATM addr\nCache-id        State      Holding time  Packets recvd  Latest IP addr   VPI VCI\n");
    168	for (eg_entry = mpc->eg_cache; eg_entry; eg_entry = eg_entry->next) {
    169		unsigned char *p = eg_entry->ctrl_info.in_MPC_data_ATM_addr;
    170		unsigned long seconds_delta = now - eg_entry->time;
    171
    172		for (i = 0; i < ATM_ESA_LEN; i++)
    173			seq_printf(m, "%02x", p[i]);
    174		seq_printf(m, "\n%-16lu%s%-14lu%-15u",
    175			   (unsigned long)ntohl(eg_entry->ctrl_info.cache_id),
    176			   egress_state_string(eg_entry->entry_state),
    177			   (eg_entry->ctrl_info.holding_time - seconds_delta),
    178			   eg_entry->packets_rcvd);
    179
    180		/* latest IP address */
    181		sprintf(ip_string, "%pI4", &eg_entry->latest_ip_addr);
    182		seq_printf(m, "%-16s", ip_string);
    183
    184		if (eg_entry->shortcut)
    185			seq_printf(m, " %-3d %-3d",
    186				   eg_entry->shortcut->vpi,
    187				   eg_entry->shortcut->vci);
    188		seq_printf(m, "\n");
    189	}
    190	seq_printf(m, "\n");
    191	return 0;
    192}
    193
    194static const struct seq_operations mpc_op = {
    195	.start =	mpc_start,
    196	.next =		mpc_next,
    197	.stop =		mpc_stop,
    198	.show =		mpc_show
    199};
    200
    201static int proc_mpc_open(struct inode *inode, struct file *file)
    202{
    203	return seq_open(file, &mpc_op);
    204}
    205
    206static ssize_t proc_mpc_write(struct file *file, const char __user *buff,
    207			      size_t nbytes, loff_t *ppos)
    208{
    209	char *page, *p;
    210	unsigned int len;
    211
    212	if (nbytes == 0)
    213		return 0;
    214
    215	if (nbytes >= PAGE_SIZE)
    216		nbytes = PAGE_SIZE-1;
    217
    218	page = (char *)__get_free_page(GFP_KERNEL);
    219	if (!page)
    220		return -ENOMEM;
    221
    222	for (p = page, len = 0; len < nbytes; p++, len++) {
    223		if (get_user(*p, buff++)) {
    224			free_page((unsigned long)page);
    225			return -EFAULT;
    226		}
    227		if (*p == '\0' || *p == '\n')
    228			break;
    229	}
    230
    231	*p = '\0';
    232
    233	if (!parse_qos(page))
    234		printk("mpoa: proc_mpc_write: could not parse '%s'\n", page);
    235
    236	free_page((unsigned long)page);
    237
    238	return len;
    239}
    240
    241static int parse_qos(const char *buff)
    242{
    243	/* possible lines look like this
    244	 * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu
    245	 */
    246	unsigned char ip[4];
    247	int tx_pcr, tx_sdu, rx_pcr, rx_sdu;
    248	__be32 ipaddr;
    249	struct atm_qos qos;
    250
    251	memset(&qos, 0, sizeof(struct atm_qos));
    252
    253	if (sscanf(buff, "del %hhu.%hhu.%hhu.%hhu",
    254			ip, ip+1, ip+2, ip+3) == 4) {
    255		ipaddr = *(__be32 *)ip;
    256		return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr));
    257	}
    258
    259	if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=tx",
    260			ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu) == 6) {
    261		rx_pcr = tx_pcr;
    262		rx_sdu = tx_sdu;
    263	} else if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=%d,%d",
    264		ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu, &rx_pcr, &rx_sdu) != 8)
    265		return 0;
    266
    267	ipaddr = *(__be32 *)ip;
    268	qos.txtp.traffic_class = ATM_CBR;
    269	qos.txtp.max_pcr = tx_pcr;
    270	qos.txtp.max_sdu = tx_sdu;
    271	qos.rxtp.traffic_class = ATM_CBR;
    272	qos.rxtp.max_pcr = rx_pcr;
    273	qos.rxtp.max_sdu = rx_sdu;
    274	qos.aal = ATM_AAL5;
    275	dprintk("parse_qos(): setting qos parameters to tx=%d,%d rx=%d,%d\n",
    276		qos.txtp.max_pcr, qos.txtp.max_sdu,
    277		qos.rxtp.max_pcr, qos.rxtp.max_sdu);
    278
    279	atm_mpoa_add_qos(ipaddr, &qos);
    280	return 1;
    281}
    282
    283/*
    284 * INITIALIZATION function - called when module is initialized/loaded.
    285 */
    286int mpc_proc_init(void)
    287{
    288	struct proc_dir_entry *p;
    289
    290	p = proc_create(STAT_FILE_NAME, 0, atm_proc_root, &mpc_proc_ops);
    291	if (!p) {
    292		pr_err("Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
    293		return -ENOMEM;
    294	}
    295	return 0;
    296}
    297
    298/*
    299 * DELETING function - called when module is removed.
    300 */
    301void mpc_proc_clean(void)
    302{
    303	remove_proc_entry(STAT_FILE_NAME, atm_proc_root);
    304}
    305
    306#endif /* CONFIG_PROC_FS */