⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 timod.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: timod.c,v 1.10 2000/07/28 12:15:02 davem Exp $ * timod.c: timod emulation. * * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz) * * Streams & timod emulation based on code * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk) * */ #include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/ioctl.h>#include <linux/fs.h>#include <linux/file.h>#include <linux/netdevice.h>#include <linux/poll.h>#include <net/sock.h>#include <asm/uaccess.h>#include <asm/termios.h>#include "conv.h"#include "socksys.h"extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, 	unsigned long arg);extern asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd,	u32 arg);asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);spinlock_t timod_pagelock = SPIN_LOCK_UNLOCKED;static char * page = NULL ;#ifndef DEBUG_SOLARIS_KMALLOC#define mykmalloc kmalloc#define mykfree kfree#elsevoid * mykmalloc(size_t s, int gfp){	static char * page;	static size_t free = 0;	void * r;	s = ((s + 63) & ~63);	if( s > PAGE_SIZE ) {		SOLD("too big size, calling real kmalloc");		return kmalloc(s, gfp);	}	if( s > free ) {		/* we are wasting memory, but we don't care */		page = (char *)__get_free_page(gfp);		free = PAGE_SIZE;	}	r = page;	page += s;	free -= s;	return r;}void mykfree(void *p){}#endif#ifndef DEBUG_SOLARIS#define BUF_SIZE	PAGE_SIZE#define PUT_MAGIC(a,m)#define SCHECK_MAGIC(a,m)#define BUF_OFFSET	0#define MKCTL_TRAILER	0#else#define BUF_SIZE	(PAGE_SIZE-2*sizeof(u64))#define BUFPAGE_MAGIC	0xBADC0DEDDEADBABEL#define MKCTL_MAGIC	0xDEADBABEBADC0DEDL#define PUT_MAGIC(a,m)	do{(*(u64*)(a))=(m);}while(0)#define SCHECK_MAGIC(a,m)	do{if((*(u64*)(a))!=(m))printk("%s,%u,%s(): magic %08x at %p corrupted!\n",\				__FILE__,__LINE__,__FUNCTION__,(m),(a));}while(0)#define BUF_OFFSET	sizeof(u64)#define MKCTL_TRAILER	sizeof(u64)#endifstatic char *getpage( void ){	char *r;	SOLD("getting page");	spin_lock(&timod_pagelock);	if (page) {		r = page;		page = NULL;		spin_unlock(&timod_pagelock);		SOLD("got cached");		return r + BUF_OFFSET;	}	spin_unlock(&timod_pagelock);	SOLD("getting new");	r = (char *)__get_free_page(GFP_KERNEL);	PUT_MAGIC(r,BUFPAGE_MAGIC);	PUT_MAGIC(r+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);	return r + BUF_OFFSET;}static void putpage(char *p){	SOLD("putting page");	p = p - BUF_OFFSET;	SCHECK_MAGIC(p,BUFPAGE_MAGIC);	SCHECK_MAGIC(p+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);	spin_lock(&timod_pagelock);	if (page) {		spin_unlock(&timod_pagelock);		free_page((unsigned long)p);		SOLD("freed it");	} else {		page = p;		spin_unlock(&timod_pagelock);		SOLD("cached it");	}}static struct T_primsg *timod_mkctl(int size){	struct T_primsg *it;	SOLD("creating primsg");	it = (struct T_primsg *)mykmalloc(size+sizeof(*it)-sizeof(s32)+2*MKCTL_TRAILER, GFP_KERNEL);	if (it) {		SOLD("got it");		it->pri = MSG_HIPRI;		it->length = size;		PUT_MAGIC((char*)((u64)(((char *)&it->type)+size+7)&~7),MKCTL_MAGIC);	}	return it;}static void timod_wake_socket(unsigned int fd){	struct socket *sock;	SOLD("wakeing socket");	sock = &current->files->fd[fd]->f_dentry->d_inode->u.socket_i;	wake_up_interruptible(&sock->wait);	read_lock(&sock->sk->callback_lock);	if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))		__kill_fasync(sock->fasync_list, SIGIO, POLL_IN);	read_unlock(&sock->sk->callback_lock);	SOLD("done");}static void timod_queue(unsigned int fd, struct T_primsg *it){	struct sol_socket_struct *sock;	SOLD("queuing primsg");	sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data;	it->next = sock->pfirst;	sock->pfirst = it;	if (!sock->plast)		sock->plast = it;	timod_wake_socket(fd);	SOLD("done");}static void timod_queue_end(unsigned int fd, struct T_primsg *it){	struct sol_socket_struct *sock;	SOLD("queuing primsg at end");	sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data;	it->next = NULL;	if (sock->plast)		sock->plast->next = it;	else		sock->pfirst = it;	sock->plast = it;	SOLD("done");}static void timod_error(unsigned int fd, int prim, int terr, int uerr){	struct T_primsg *it;		SOLD("making error");	it = timod_mkctl(sizeof(struct T_error_ack));	if (it) {		struct T_error_ack *err = (struct T_error_ack *)&it->type;				SOLD("got it");		err->PRIM_type = T_ERROR_ACK;		err->ERROR_prim = prim;		err->TLI_error = terr;		err->UNIX_error = uerr; /* FIXME: convert this */		timod_queue(fd, it);	}	SOLD("done");}static void timod_ok(unsigned int fd, int prim){	struct T_primsg *it;	struct T_ok_ack *ok;		SOLD("creating ok ack");	it = timod_mkctl(sizeof(*ok));	if (it) {		SOLD("got it");		ok = (struct T_ok_ack *)&it->type;		ok->PRIM_type = T_OK_ACK;		ok->CORRECT_prim = prim;		timod_queue(fd, it);	}	SOLD("done");}static int timod_optmgmt(unsigned int fd, int flag, char *opt_buf, int opt_len, int do_ret){	int error, failed;	int ret_space, ret_len;	long args[5];	char *ret_pos,*ret_buf;	int (*sys_socketcall)(int, unsigned long *) =		(int (*)(int, unsigned long *))SYS(socketcall);	mm_segment_t old_fs = get_fs();	SOLD("entry");	SOLDD(("fd %u flg %u buf %p len %u doret %u",fd,flag,opt_buf,opt_len,do_ret));	if (!do_ret && (!opt_buf || opt_len <= 0))		return 0;	SOLD("getting page");	ret_pos = ret_buf = getpage();	ret_space = BUF_SIZE;	ret_len = 0;		error = failed = 0;	SOLD("looping");	while(opt_len >= sizeof(struct opthdr)) {		struct opthdr *opt;		int orig_opt_len; 		SOLD("loop start");		opt = (struct opthdr *)ret_pos; 		if (ret_space < sizeof(struct opthdr)) {			failed = TSYSERR;			break;		}		SOLD("getting opthdr");		if (copy_from_user(opt, opt_buf, sizeof(struct opthdr)) ||			opt->len > opt_len) {			failed = TBADOPT;			break;		}		SOLD("got opthdr");		if (flag == T_NEGOTIATE) {			char *buf;						SOLD("handling T_NEGOTIATE");			buf = ret_pos + sizeof(struct opthdr);			if (ret_space < opt->len + sizeof(struct opthdr) ||				copy_from_user(buf, opt_buf+sizeof(struct opthdr), opt->len)) {				failed = TSYSERR;				break;			}			SOLD("got optdata");			args[0] = fd;			args[1] = opt->level;			args[2] = opt->name;			args[3] = (long)buf;			args[4] = opt->len;			SOLD("calling SETSOCKOPT");			set_fs(KERNEL_DS);			error = sys_socketcall(SYS_SETSOCKOPT, args);			set_fs(old_fs);			if (error) {				failed = TBADOPT;				break;			}			SOLD("SETSOCKOPT ok");		}		orig_opt_len = opt->len;		opt->len = ret_space - sizeof(struct opthdr);		if (opt->len < 0) {			failed = TSYSERR;			break;		}		args[0] = fd;		args[1] = opt->level;		args[2] = opt->name;		args[3] = (long)(ret_pos+sizeof(struct opthdr));		args[4] = (long)&opt->len;		SOLD("calling GETSOCKOPT");		set_fs(KERNEL_DS);		error = sys_socketcall(SYS_GETSOCKOPT, args);		set_fs(old_fs);;		if (error) {			failed = TBADOPT;			break;		}		SOLD("GETSOCKOPT ok");		ret_space -= sizeof(struct opthdr) + opt->len;		ret_len += sizeof(struct opthdr) + opt->len;		ret_pos += sizeof(struct opthdr) + opt->len;		opt_len -= sizeof(struct opthdr) + orig_opt_len;		opt_buf += sizeof(struct opthdr) + orig_opt_len;		SOLD("loop end");	}	SOLD("loop done");	if (do_ret) {		SOLD("generating ret msg");		if (failed)			timod_error(fd, T_OPTMGMT_REQ, failed, -error);		else {			struct T_primsg *it;			it = timod_mkctl(sizeof(struct T_optmgmt_ack) + ret_len);			if (it) {				struct T_optmgmt_ack *ack =					(struct T_optmgmt_ack *)&it->type;				SOLD("got primsg");				ack->PRIM_type = T_OPTMGMT_ACK;				ack->OPT_length = ret_len;				ack->OPT_offset = sizeof(struct T_optmgmt_ack);				ack->MGMT_flags = (failed ? T_FAILURE : flag);				memcpy(((char*)ack)+sizeof(struct T_optmgmt_ack),					ret_buf, ret_len);				timod_queue(fd, it);			}		}	}	SOLDD(("put_page %p\n", ret_buf));	putpage(ret_buf);	SOLD("done");		return 0;}int timod_putmsg(unsigned int fd, char *ctl_buf, int ctl_len,			char *data_buf, int data_len, int flags){	int ret, error, terror;	char *buf;	struct file *filp;	struct inode *ino;	struct sol_socket_struct *sock;	mm_segment_t old_fs = get_fs();	long args[6];	int (*sys_socketcall)(int, unsigned long *) =		(int (*)(int, unsigned long *))SYS(socketcall);	int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int) =		(int (*)(int, void *, size_t, unsigned, struct sockaddr *, int))SYS(sendto);	filp = current->files->fd[fd];	ino = filp->f_dentry->d_inode;	sock = (struct sol_socket_struct *)filp->private_data;	SOLD("entry");	if (get_user(ret, (int *)A(ctl_buf)))		return -EFAULT;	switch (ret) {	case T_BIND_REQ:	{		struct T_bind_req req;				SOLDD(("bind %016lx(%016lx)\n", sock, filp));		SOLD("T_BIND_REQ");		if (sock->state != TS_UNBND) {			timod_error(fd, T_BIND_REQ, TOUTSTATE, 0);			return 0;		}		SOLD("state ok");		if (copy_from_user(&req, ctl_buf, sizeof(req))) {			timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);			return 0;		}		SOLD("got ctl req");		if (req.ADDR_offset && req.ADDR_length) {			if (req.ADDR_length > BUF_SIZE) {				timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);				return 0;			}			SOLD("req size ok");			buf = getpage();			if (copy_from_user(buf, ctl_buf + req.ADDR_offset, req.ADDR_length)) {				timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);				putpage(buf);				return 0;			}			SOLD("got ctl data");			args[0] = fd;			args[1] = (long)buf;			args[2] = req.ADDR_length;			SOLD("calling BIND");			set_fs(KERNEL_DS);			error = sys_socketcall(SYS_BIND, args);			set_fs(old_fs);			putpage(buf);			SOLD("BIND returned");		} else 			error = 0;		if (!error) {			struct T_primsg *it;			if (req.CONIND_number) {	  			args[0] = fd;  				args[1] = req.CONIND_number;  				SOLD("calling LISTEN");  				set_fs(KERNEL_DS);	  			error = sys_socketcall(SYS_LISTEN, args);  				set_fs(old_fs);  				SOLD("LISTEN done");  			}			it = timod_mkctl(sizeof(struct T_bind_ack)+sizeof(struct sockaddr));			if (it) {				struct T_bind_ack *ack;				ack = (struct T_bind_ack *)&it->type;				ack->PRIM_type = T_BIND_ACK;				ack->ADDR_offset = sizeof(*ack);				ack->ADDR_length = sizeof(struct sockaddr);				ack->CONIND_number = req.CONIND_number;				args[0] = fd;				args[1] = (long)(ack+sizeof(*ack));				args[2] = (long)&ack->ADDR_length;				set_fs(KERNEL_DS);				sys_socketcall(SYS_GETSOCKNAME,args);				set_fs(old_fs);				sock->state = TS_IDLE;				timod_ok(fd, T_BIND_REQ);				timod_queue_end(fd, it);				SOLD("BIND done");				return 0;			}		}		SOLD("some error");		switch (error) {			case -EINVAL:				terror = TOUTSTATE;				error = 0;				break;			case -EACCES:				terror = TACCES;				error = 0;				break;			case -EADDRNOTAVAIL:			case -EADDRINUSE:				terror = TNOADDR;				error = 0;				break;			default:				terror = TSYSERR;				break;		}		timod_error(fd, T_BIND_REQ, terror, -error);		SOLD("BIND done");		return 0;	}	case T_CONN_REQ:	{		struct T_conn_req req;		unsigned short oldflags;		struct T_primsg *it;		SOLD("T_CONN_REQ");		if (sock->state != TS_UNBND && sock->state != TS_IDLE) {			timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);			return 0;		}		SOLD("state ok");		if (copy_from_user(&req, ctl_buf, sizeof(req))) {			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);			return 0;		}		SOLD("got ctl req");		if (ctl_len > BUF_SIZE) {			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);			return 0;		}		SOLD("req size ok");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -