summaryrefslogblamecommitdiffstats
path: root/iv/orodja/ldmitm/tcp_times.c
blob: 09968575bf7c5f8eef350a83433d3ddbd38fd4ce (plain) (tree)




















































































































                                                                                
/*
Prevajanje: make
Namestitev v jedro: insmod tcp_times.ko
Uporaba v C:
#include <stdint.h>
#include "tcp_times.h"
int tcp_times = open("/proc/tcp_times", O_RDWR);
if (tcp_times == -1) {
	perror("open tcp_times");
	break;
}
int tcpsock = accept(boundsocket, &address, &addrlen);
struct tcp_times tt = {
	.fd = tcpsock
};
if (ioctl(tcp_times, 0, &tt) == -1) {
	perror("ioctl tcp_times");
	break;
}
// sedaj so polja v tt populirana
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/net.h>
#include <linux/tcp.h>
#include <linux/version.h>
#include "tcp_times.h"
#define MIN(a,b) (((a)<(b))?(a):(b))
MODULE_AUTHOR("Anton Luka Šijanec <anton@sijanec.eu>");
MODULE_DESCRIPTION("tcp last received tsval, rtt procfs ioctl driver");
MODULE_LICENSE("");
static struct proc_dir_entry * ent;
static long myioctl (struct file * filep, unsigned int cmd, unsigned long arg) {
	switch(cmd) {
		case 0:
			struct tcp_times tt;
			if (copy_from_user(&tt, (void *) arg, sizeof tt))
				return -EFAULT;
			struct fd f = fdget(tt.fd);
			if (!f.file)
				return -EBADF;
			struct socket * sock = sock_from_file(f.file);
			if (!sock) {
				fdput(f);
				return -ENOTSOCK;
			}
			if (!(sock->type & SOCK_STREAM)) {
				fdput(f);
				return -ENOSTR;
			}
			if (!sock->sk) {
				fdput(f);
				return -EBADFD;
			}
			if (sock->sk->sk_protocol != IPPROTO_TCP) {
				fdput(f);
				return -ESOCKTNOSUPPORT;
			}
			struct tcp_sock * tp = tcp_sk(sock->sk);
			tt.ts_recent_stamp = tp->rx_opt.ts_recent_stamp;
			tt.ts_recent = tp->rx_opt.ts_recent;
			tt.rcv_tsval = tp->rx_opt.rcv_tsval;
			tt.rcv_tsecr = tp->rx_opt.rcv_tsecr;
			tt.saw_tstamp = tp->rx_opt.saw_tstamp;
			tt.tstamp_ok = tp->rx_opt.tstamp_ok;
			tt.dsack = tp->rx_opt.dsack;
			tt.wscale_ok = tp->rx_opt.wscale_ok;
			tt.sack_ok = tp->rx_opt.sack_ok;
			tt.smc_ok = tp->rx_opt.smc_ok;
			tt.snd_wscale = tp->rx_opt.snd_wscale;
			tt.rcv_wscale = tp->rx_opt.rcv_wscale;
			tt.advmss = tp->advmss;
			tt.rttvar_us = tp->rttvar_us;
			tt.srtt_us = tp->srtt_us;
			tt.rcv_rtt_est.rtt_us = tp->rcv_rtt_est.rtt_us;
			tt.rcv_rtt_est.seq = tp->rcv_rtt_est.seq;
			tt.rcv_rtt_est.time = tp->rcv_rtt_est.time;
			tt.rtt_us = tp->rack.rtt_us;
			tt.mdev_max_us = tp->mdev_max_us;
			fdput(f);
			if (copy_to_user((void *) arg, &tt, sizeof tt)) {
				fdput(f);
				return -EFAULT;
			}
			return 0;
		default:
			return -EINVAL;
	}
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
static const struct file_operations ops = {
	.owner = THIS_MODULE,
	.unlocked_ioctl = myioctl,
};
#else
static const struct proc_ops ops = {
	.proc_ioctl = myioctl,
};
#endif
static int __init custom_init (void) {
	ent = proc_create("tcp_times", 0666, NULL, &ops);
	if (!ent) {
		printk(KERN_INFO "tcp_times failed to create procfs entry.");
		return -EINVAL;
	}
	printk(KERN_INFO "tcp_times kernel module loaded.");
	return 0;
}
static void __exit custom_exit (void) {
	proc_remove(ent);
	printk(KERN_INFO "tcp_times kernel module exiting ...");
}
module_init(custom_init);
module_exit(custom_exit);