 f737eea636
			
		
	
	
		f737eea636
		
	
	
	
	
		
			
			- synchronize request type with ioctl by making it unsigned long; - unbreak VFS requests, as they were being sent to PM; - use proper ioctl direction flags (and new numbers) for requests; - remove some needless header inclusions; - svrctl is in libc, make its message name reflect this; - keep backward compatibility: svrctl is part of the userland ABI. Change-Id: I44902e8d0d11b8ebc1ef3bda94d2202481743c9b
		
			
				
	
	
		
			385 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			385 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
| inet/qp.c
 | |
| 
 | |
| Query parameters
 | |
| 
 | |
| Created:	June 1995 by Philip Homburg <philip@f-mnx.phicoh.com>
 | |
| */
 | |
| 
 | |
| #include "inet.h"
 | |
| #include "generic/assert.h"
 | |
| 
 | |
| #include "queryparam.h"
 | |
| 
 | |
| #include "generic/buf.h"
 | |
| #include "generic/clock.h"
 | |
| #include "generic/event.h"
 | |
| #include "generic/type.h"
 | |
| #include "generic/sr.h"
 | |
| 
 | |
| #include "generic/tcp_int.h"
 | |
| #include "generic/udp_int.h"
 | |
| #include "mq.h"
 | |
| #include "qp.h"
 | |
| #include "sr_int.h"
 | |
| 
 | |
| THIS_FILE
 | |
| 
 | |
| #define MAX_REQ	1024	/* Maximum size of a request */
 | |
| 
 | |
| #define QP_FD_NR	4
 | |
| 
 | |
| typedef struct qp_fd
 | |
| {
 | |
| 	int qf_flags;
 | |
| 	int qf_srfd;
 | |
| 	get_userdata_t qf_get_userdata;
 | |
| 	put_userdata_t qf_put_userdata;
 | |
| 	acc_t *qf_req_pkt;
 | |
| } qp_fd_t;
 | |
| 
 | |
| #define QFF_EMPTY	0
 | |
| #define QFF_INUSE	1
 | |
| 
 | |
| static qp_fd_t qp_fd_table[QP_FD_NR];
 | |
| 
 | |
| static struct export_param_list inet_ex_list[]=
 | |
| {
 | |
| 	QP_VARIABLE(sr_fd_table),
 | |
| 	QP_VARIABLE(ip_dev),
 | |
| 	QP_VARIABLE(tcp_fd_table),
 | |
| 	QP_VARIABLE(tcp_conn_table),
 | |
| 	QP_VARIABLE(tcp_cancel_f),
 | |
| 	QP_VECTOR(udp_port_table, udp_port_table, ip_conf_nr),
 | |
| 	QP_VARIABLE(udp_fd_table),
 | |
| 	QP_END()
 | |
| };
 | |
| 
 | |
| static struct export_params inet_ex_params= { inet_ex_list, NULL };
 | |
| 
 | |
| static struct queryvars {
 | |
| 	/* Input */
 | |
| 	acc_t *param;
 | |
| 
 | |
| 	/* Output */
 | |
| 	qp_fd_t *qp_fd;
 | |
| 	off_t fd_offset;
 | |
| 	size_t rd_bytes_left;
 | |
| 	off_t outbuf_off;
 | |
| 	char outbuf[256];
 | |
| 
 | |
| 	int r;	/* result */
 | |
| } *qvars;
 | |
| 
 | |
| 
 | |
| static int  qp_open ARGS(( int port, int srfd,
 | |
| 	get_userdata_t get_userdata, put_userdata_t put_userdata,
 | |
| 	put_pkt_t put_pkt, select_res_t select_res ));
 | |
| static void qp_close ARGS(( int fd ));
 | |
| static int qp_read ARGS(( int fd, size_t count ));
 | |
| static int qp_write ARGS(( int fd, size_t count ));
 | |
| static int qp_ioctl ARGS(( int fd, ioreq_t req ));
 | |
| static int qp_cancel ARGS(( int fd, int which_operation ));
 | |
| static int qp_select ARGS(( int fd, unsigned operations ));
 | |
| static qp_fd_t *get_qp_fd ARGS(( int fd ));
 | |
| static int do_query ARGS(( qp_fd_t *qp_fd, acc_t *pkt, int count ));
 | |
| static int qp_getc ARGS(( void ));
 | |
| static void qp_putc ARGS(( struct queryvars *qv, int c ));
 | |
| static void qp_buffree ARGS(( int priority ));
 | |
| #ifdef BUF_CONSISTENCY_CHECK
 | |
| static void qp_bufcheck ARGS(( void ));
 | |
| #endif
 | |
| 
 | |
| void qp_init()
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	qp_export(&inet_ex_params);
 | |
| 
 | |
| 	for (i= 0; i<QP_FD_NR; i++)
 | |
| 		qp_fd_table[i].qf_flags= QFF_EMPTY;
 | |
| 
 | |
| #ifndef BUF_CONSISTENCY_CHECK
 | |
| 	bf_logon(qp_buffree);
 | |
| #else
 | |
| 	bf_logon(qp_buffree, qp_bufcheck);
 | |
| #endif
 | |
| 
 | |
| 	sr_add_minor(IPSTAT_MINOR, 0, qp_open, qp_close, qp_read, qp_write,
 | |
| 		qp_ioctl, qp_cancel, qp_select);
 | |
| }
 | |
| 
 | |
| static int qp_open(port, srfd, get_userdata, put_userdata, put_pkt,
 | |
| 	select_res)
 | |
| int port;
 | |
| int srfd;
 | |
| get_userdata_t get_userdata;
 | |
| put_userdata_t put_userdata;
 | |
| put_pkt_t put_pkt;
 | |
| select_res_t select_res;
 | |
| {
 | |
| 	int i;
 | |
| 	qp_fd_t *qp_fd;
 | |
| 
 | |
| 	for (i= 0; i< QP_FD_NR; i++)
 | |
| 	{
 | |
| 		if (!(qp_fd_table[i].qf_flags & QFF_INUSE))
 | |
| 			break;
 | |
| 	}
 | |
| 	if (i >= QP_FD_NR)
 | |
| 		return EAGAIN;
 | |
| 	qp_fd= &qp_fd_table[i];
 | |
| 	qp_fd->qf_flags= QFF_INUSE;
 | |
| 	qp_fd->qf_srfd= srfd;
 | |
| 	qp_fd->qf_get_userdata= get_userdata;
 | |
| 	qp_fd->qf_put_userdata= put_userdata;
 | |
| 	qp_fd->qf_req_pkt= NULL;
 | |
| 
 | |
| 	return i;
 | |
| }
 | |
| 
 | |
| static void qp_close(fd)
 | |
| int fd;
 | |
| {
 | |
| 	qp_fd_t *qp_fd;
 | |
| 
 | |
| 	qp_fd= get_qp_fd(fd);
 | |
| 	qp_fd->qf_flags= QFF_EMPTY;
 | |
| 	if (qp_fd->qf_req_pkt)
 | |
| 	{
 | |
| 		bf_afree(qp_fd->qf_req_pkt);
 | |
| 		qp_fd->qf_req_pkt= NULL;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static int qp_read(fd, count)
 | |
| int fd;
 | |
| size_t count;
 | |
| {
 | |
| 	int r;
 | |
| 	acc_t *pkt;
 | |
| 	qp_fd_t *qp_fd;
 | |
| 
 | |
| 	qp_fd= get_qp_fd(fd);
 | |
| 	pkt= qp_fd->qf_req_pkt;
 | |
| 	qp_fd->qf_req_pkt= NULL;
 | |
| 	if (!pkt)
 | |
| 	{
 | |
| 		/* Nothing to do */
 | |
| 		qp_fd->qf_put_userdata(qp_fd->qf_srfd, EIO, 0,
 | |
| 			FALSE /* !for_ioctl*/);
 | |
| 		return OK;
 | |
| 	}
 | |
| 	r= do_query(qp_fd, pkt, count);
 | |
| 	qp_fd->qf_put_userdata(qp_fd->qf_srfd, r, 0,
 | |
| 			FALSE /* !for_ioctl*/);
 | |
| 	return OK;
 | |
| }
 | |
| 
 | |
| static int qp_write(fd, count)
 | |
| int fd;
 | |
| size_t count;
 | |
| {
 | |
| 	acc_t *pkt;
 | |
| 	qp_fd_t *qp_fd;
 | |
| 
 | |
| 	qp_fd= get_qp_fd(fd);
 | |
| 	if (count > MAX_REQ)
 | |
| 	{
 | |
| 		qp_fd->qf_get_userdata(qp_fd->qf_srfd, ENOMEM, 0,
 | |
| 			FALSE /* !for_ioctl*/);
 | |
| 		return OK;
 | |
| 	}
 | |
| 	pkt= qp_fd->qf_get_userdata(qp_fd->qf_srfd, 0, count,
 | |
| 		FALSE /* !for_ioctl*/);
 | |
| 	if (!pkt)
 | |
| 	{
 | |
| 		qp_fd->qf_get_userdata(qp_fd->qf_srfd, EFAULT, 0,
 | |
| 			FALSE /* !for_ioctl*/);
 | |
| 		return OK;
 | |
| 	}
 | |
| 	if (qp_fd->qf_req_pkt)
 | |
| 	{
 | |
| 		bf_afree(qp_fd->qf_req_pkt);
 | |
| 		qp_fd->qf_req_pkt= NULL;
 | |
| 	}
 | |
| 	qp_fd->qf_req_pkt= pkt;
 | |
| 	qp_fd->qf_get_userdata(qp_fd->qf_srfd, count, 0,
 | |
| 		FALSE /* !for_ioctl*/);
 | |
| 	return OK;
 | |
| }
 | |
| 
 | |
| static int qp_ioctl(fd, req)
 | |
| int fd;
 | |
| ioreq_t req;
 | |
| {
 | |
| 	qp_fd_t *qp_fd;
 | |
| 
 | |
| 	qp_fd= get_qp_fd(fd);
 | |
| 	qp_fd->qf_get_userdata(qp_fd->qf_srfd, ENOTTY, 0,
 | |
| 			TRUE /* for_ioctl*/);
 | |
| 	return OK;
 | |
| }
 | |
| 
 | |
| static int qp_cancel(fd, which_operation)
 | |
| int fd;
 | |
| int which_operation;
 | |
| {
 | |
| 	ip_panic(( "qp_cancel: should not be here, no blocking calls" ));
 | |
| 	return OK;
 | |
| }
 | |
| 
 | |
| static int qp_select(fd, operations)
 | |
| int fd;
 | |
| unsigned operations;
 | |
| {
 | |
| 	unsigned resops;
 | |
| 
 | |
| 	resops= 0;
 | |
| 	if (operations & SR_SELECT_READ)
 | |
| 		resops |= SR_SELECT_READ;
 | |
| 	if (operations & SR_SELECT_WRITE)
 | |
| 		resops |= SR_SELECT_WRITE;
 | |
| 	return resops;
 | |
| }
 | |
| 
 | |
| static qp_fd_t *get_qp_fd(fd)
 | |
| int fd;
 | |
| {
 | |
| 	qp_fd_t *qp_fd;
 | |
| 
 | |
| 	assert(fd >= 0 && fd < QP_FD_NR);
 | |
| 	qp_fd= &qp_fd_table[fd];
 | |
| 	assert(qp_fd->qf_flags & QFF_INUSE);
 | |
| 	return qp_fd;
 | |
| }
 | |
| 
 | |
| static int do_query(qp_fd, pkt, count)
 | |
| qp_fd_t *qp_fd;
 | |
| acc_t *pkt;
 | |
| int count;
 | |
| {
 | |
| 	struct queryvars qv;
 | |
| 	void *addr;
 | |
| 	size_t n, size;
 | |
| 	int byte;
 | |
| 	int more;
 | |
| 	static char hex[]= "0123456789ABCDEF";
 | |
| 
 | |
| 	qvars= &qv;
 | |
| 	qv.param= pkt; pkt= NULL;
 | |
| 	qv.qp_fd= qp_fd;
 | |
| 	qv.fd_offset= 0;
 | |
| 	qv.outbuf_off= 0;
 | |
| 	qv.rd_bytes_left= count;
 | |
| 	qv.r= 0;
 | |
| 
 | |
| 	do {
 | |
| 		more= queryparam(qp_getc, &addr, &size);
 | |
| 		for (n= 0; n < size; n++) {
 | |
| 			byte= ((u8_t *) addr)[n];
 | |
| 			qp_putc(&qv, hex[byte >> 4]);
 | |
| 			qp_putc(&qv, hex[byte & 0x0F]);
 | |
| 		}
 | |
| 		qp_putc(&qv, more ? ',' : 0);
 | |
| 		if (qv.r)
 | |
| 			break;
 | |
| 	} while (more);
 | |
| 	if (qv.param)
 | |
| 	{
 | |
| 		assert(0);
 | |
| 		bf_afree(qv.param);
 | |
| 		qv.param= NULL;
 | |
| 	}
 | |
| 	if (qv.r)
 | |
| 		return qv.r;
 | |
| 	return qv.fd_offset;
 | |
| }
 | |
| 
 | |
| static int qp_getc()
 | |
| {
 | |
| 	/* Return one character of the names to search for. */
 | |
| 	acc_t *pkt;
 | |
| 	struct queryvars *qv= qvars;
 | |
| 	u8_t c;
 | |
| 
 | |
| 	pkt= qv->param;
 | |
| 	qv->param= NULL;
 | |
| 	if (pkt == NULL)
 | |
| 		return 0;
 | |
| 
 | |
| 	assert(bf_bufsize(pkt) > 0);
 | |
| 	c= ptr2acc_data(pkt)[0];
 | |
| 	if (bf_bufsize(pkt) > 1)
 | |
| 		qv->param= bf_delhead(pkt, 1);
 | |
| 	else
 | |
| 	{
 | |
| 		bf_afree(pkt);
 | |
| 		qv->param= NULL;
 | |
| 	}
 | |
| 
 | |
| 	return c;
 | |
| }
 | |
| 
 | |
| static void qp_putc(qv, c)
 | |
| struct queryvars *qv;
 | |
| int c;
 | |
| {
 | |
| 	/* Send one character back to the user. */
 | |
| 	acc_t *pkt;
 | |
| 	qp_fd_t *qp_fd;
 | |
| 	size_t bytes_left;
 | |
| 	off_t off;
 | |
| 
 | |
| 	bytes_left= qv->rd_bytes_left;
 | |
| 	if (qv->r || bytes_left == 0)
 | |
| 		return;
 | |
| 
 | |
| 	off= qv->outbuf_off;
 | |
| 	assert(off < sizeof(qv->outbuf));
 | |
| 	qv->outbuf[off]= c;
 | |
| 	off++;
 | |
| 	bytes_left--;
 | |
| 	qv->rd_bytes_left= bytes_left;
 | |
| 	if (c != '\0' && off < sizeof(qv->outbuf) && bytes_left != 0)
 | |
| 	{
 | |
| 		qv->outbuf_off= off;
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	pkt= bf_memreq(off);
 | |
| 	assert(pkt->acc_next == NULL);
 | |
| 	memcpy(ptr2acc_data(pkt), qv->outbuf, off);
 | |
| 	qp_fd= qv->qp_fd;
 | |
| 	qv->r= qp_fd->qf_put_userdata(qp_fd->qf_srfd, qv->fd_offset,
 | |
| 		pkt, FALSE /* !for_ioctl*/ );
 | |
| 	qv->fd_offset += off;
 | |
| 	qv->outbuf_off= 0;
 | |
| }
 | |
| 
 | |
| static void qp_buffree (priority)
 | |
| int priority;
 | |
| {
 | |
| 	/* For the moment, we are not going to free anything */
 | |
| }
 | |
| 
 | |
| #ifdef BUF_CONSISTENCY_CHECK
 | |
| static void qp_bufcheck()
 | |
| {
 | |
| 	int i;
 | |
| 	qp_fd_t *qp_fd;
 | |
| 
 | |
| 	for (i= 0, qp_fd= qp_fd_table; i<QP_FD_NR; i++, qp_fd++)
 | |
| 	{
 | |
| 		if (!(qp_fd->qf_flags & QFF_INUSE))
 | |
| 			continue;
 | |
| 		if (qp_fd->qf_req_pkt)
 | |
| 			bf_check_acc(qp_fd->qf_req_pkt);
 | |
| 	}
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * $PchId: qp.c,v 1.7 2005/06/28 14:25:25 philip Exp $
 | |
|  */
 |