Minix2.0/src/inet/sr.c

/*	this file contains the interface of the network software with the file
	system.

The valid messages and their parameters are:

 __________________________________________________________________
|		|           |         |       |          |         |
| m_type	|   DEVICE  | PROC_NR |	COUNT |	REQUEST  | ADDRESS |
|_______________|___________|_________|_______|__________|_________|
|		|           |         |       |          |         |
| NW_OPEN 	| minor dev | proc nr | mode  |          |         |
|_______________|___________|_________|_______|__________|_________|
|		|           |         |       |          |         |
| NW_CLOSE 	| minor dev | proc nr |       |          |         |
|_______________|___________|_________|_______|__________|_________|
|		|           |         |       |          |         |
| NW_IOCTL	| minor dev | proc nr |       |	NWIO..	 | address |
|_______________|___________|_________|_______|__________|_________|
|		|           |         |       |          |         |
| NW_READ	| minor dev | proc nr |	count |          | address |
|_______________|___________|_________|_______|__________|_________|
|		|           |         |       |          |         |
| NW_WRITE	| minor dev | proc nr |	count |          | address |
|_______________|___________|_________|_______|__________|_________|
|		|           |         |       |          |         |
| NW_CANCEL	| minor dev | proc nr |       |          |         |
|_______________|___________|_________|_______|__________|_________|

*/

#include "inet.h"
#include <minix/callnr.h>
#include "mq.h"
#include "proto.h"
#include "generic/assert.h"
#include "generic/buf.h"
#include "generic/sr.h"
#include "generic/type.h"

INIT_PANIC();

#define FD_NR			32

typedef struct sr_fd
{
	int srf_flags;
	int srf_fd;
	int srf_port;
	sr_open_t srf_open;
	sr_close_t srf_close;
	sr_write_t srf_write;
	sr_read_t srf_read;
	sr_ioctl_t srf_ioctl;
	sr_cancel_t srf_cancel;
	mq_t *srf_ioctl_q, *srf_ioctl_q_tail;
	mq_t *srf_read_q, *srf_read_q_tail;
	mq_t *srf_write_q, *srf_write_q_tail;
} sr_fd_t;

#define SFF_FLAGS 	0x0F
#	define SFF_FREE		0x00
#	define SFF_MINOR	0x01
#	define SFF_INUSE	0x02
#	define SFF_BUSY		0x3C
#		define SFF_IOCTL_IP	0x04
#		define SFF_READ_IP	0x08
#		define SFF_WRITE_IP	0x10
#	define SFF_PENDING_REQ	0x30
#	define SFF_SUSPENDED	0x1C0
#		define SFF_IOCTL_SUSP	0x40
#		define SFF_READ_SUSP	0x80
#		define SFF_WRITE_SUSP	0x100

FORWARD _PROTOTYPE ( int sr_open, (message *m) );
FORWARD _PROTOTYPE ( void sr_close, (message *m) );
FORWARD _PROTOTYPE ( int sr_rwio, (mq_t *m) );
FORWARD _PROTOTYPE ( int sr_cancel, (message *m) );
FORWARD _PROTOTYPE ( void sr_reply, (message *mes_ptr, int reply) );
FORWARD _PROTOTYPE ( void sr_revive, (mq_t *mes_ptr, int reply) );
FORWARD _PROTOTYPE ( sr_fd_t *sr_getchannel, (int minor));
FORWARD _PROTOTYPE ( acc_t *sr_get_userdata, (int fd, vir_bytes offset,
					vir_bytes count, int for_ioctl) );
FORWARD _PROTOTYPE ( int sr_put_userdata, (int fd, vir_bytes offset,
						acc_t *data, int for_ioctl) );
FORWARD _PROTOTYPE ( int sr_repl_queue, (int proc) );
FORWARD _PROTOTYPE ( int walk_queue, (sr_fd_t *sr_fd, mq_t *q_head, 
				mq_t **q_tail_ptr, int type, int proc_n) );
FORWARD _PROTOTYPE ( void process_req_q, (mq_t *mq, mq_t *tail, 
							mq_t **tail_ptr) );
FORWARD _PROTOTYPE ( int cp_u2b, (int proc, char *src, acc_t **var_acc_ptr,
								 int size) );
FORWARD _PROTOTYPE ( int cp_b2u, (acc_t *acc_ptr, int proc, char *dest) );

PRIVATE sr_fd_t sr_fd_table[FD_NR];
PRIVATE mq_t *repl_queue, *repl_queue_tail;
PRIVATE cpvec_t cpvec[CPVEC_NR];

PUBLIC void sr_init()
{
	int i;

	for (i=0; i<FD_NR; i++)
		sr_fd_table[i].srf_flags= SFF_FREE;
	repl_queue= NULL;
}

PUBLIC void sr_rec(m)
mq_t *m;
{
	message mess, *mp;
	int result;
	int send_reply, free_mess;

	if (repl_queue)
	{
		if (m->mq_mess.m_type == NW_CANCEL)
		{
			result= sr_repl_queue(m->mq_mess.PROC_NR);
			if (result)
				return;	/* canceled request in queue */
		}
		else
			sr_repl_queue(ANY);
	}

#if DEBUG & 256
 { where(); printf("sr_rec: message from %d for %d type %d, minor %d\n",
	m->mq_mess.m_source, m->mq_mess.PROC_NR, m->mq_mess.m_type, 
	m->mq_mess.DEVICE); }
#endif
	switch (m->mq_mess.m_type)
	{
	case NW_OPEN:
		result= sr_open(&m->mq_mess);
		send_reply= 1;
		free_mess= 1;
		break;
	case NW_CLOSE:
		sr_close(&m->mq_mess);
		result= OK;
		send_reply= 1;
		free_mess= 1;
		break;
	case NW_READ:
	case NW_WRITE:
	case NW_IOCTL:
#if DEBUG & 256
 { where(); printf("calling rwio\n"); }
#endif
		result= sr_rwio(m);
#if DEBUG & 256
 { where(); printf("rwio()= %d\n", result); }
#endif
assert(result == OK || result == SUSPEND);
		send_reply= (result == SUSPEND);
		free_mess= 0;
		break;
	case NW_CANCEL:
		result= sr_cancel(&m->mq_mess);
assert(result == OK || result == EINTR);
		send_reply= (result == EINTR);
		free_mess= 1;
		break;
	default:
		ip_panic(("unknown message, type= %d", m->mq_mess.m_type));
	}
	if (send_reply)
	{
		if (free_mess)
			mp= &m->mq_mess;
		else
		{
			mess= m->mq_mess;
			mp= &mess;
		}
		sr_reply(mp, result);
	}
	if (free_mess)
		mq_free(m);
}

PUBLIC int sr_add_minor(minor, port, openf, closef, readf, writef,
	ioctlf, cancelf)
int minor;
int port;
sr_open_t openf;
sr_close_t closef;
sr_read_t readf;
sr_write_t writef;
sr_ioctl_t ioctlf;
sr_cancel_t cancelf;
{
	sr_fd_t *sr_fd;

	assert (minor>=0 && minor<FD_NR);

	sr_fd= &sr_fd_table[minor];

	if (sr_fd->srf_flags & SFF_INUSE)
		return EGENERIC;

	sr_fd->srf_flags= SFF_INUSE | SFF_MINOR;
	sr_fd->srf_port= port;
	sr_fd->srf_open= openf;
	sr_fd->srf_close= closef;
	sr_fd->srf_write= writef;
	sr_fd->srf_read= readf;
	sr_fd->srf_ioctl= ioctlf;
	sr_fd->srf_cancel= cancelf;

	return OK;
}

PRIVATE int sr_open(m)
message *m;
{
	sr_fd_t *sr_fd;

	int minor= m->DEVICE;
	int i, fd;

	if (minor<0 || minor>FD_NR)
	{
#if DEBUG
 { where(); printf("replying EINVAL\n"); }
#endif
		return EINVAL;
	}
	if (!(sr_fd_table[minor].srf_flags & SFF_MINOR))
	{
#if DEBUG
 { where(); printf("replying ENXIO\n"); }
#endif
		return ENXIO;
	}
	for (i=0; i<FD_NR && (sr_fd_table[i].srf_flags & SFF_INUSE); i++);

	if (i>=FD_NR)
	{
#if DEBUG
 { where(); printf("replying ENFILE\n"); }
#endif
		return ENFILE;
	}

	sr_fd= &sr_fd_table[i];
	*sr_fd= sr_fd_table[minor];
	sr_fd->srf_flags= SFF_INUSE;
	fd= (*sr_fd->srf_open)(sr_fd->srf_port, i, sr_get_userdata,
		sr_put_userdata);
#if DEBUG & 256
 { where(); printf("srf_open: 0x%x(%d, %d, .., ..)= %d\n", sr_fd->srf_open,
	sr_fd->srf_port, i, fd); }
#endif
	if (fd<0)
	{
		sr_fd->srf_flags= SFF_FREE;
#if DEBUG
 { where(); printf("replying %d\n", fd); }
#endif
		return fd;
	}
	sr_fd->srf_fd= fd;
#if DEBUG & 256
 { where(); printf("replying %d\n", i); }
#endif
	return i;
}

PRIVATE void sr_close(m)
message *m;
{
	sr_fd_t *sr_fd;

	sr_fd= sr_getchannel(m->DEVICE);
	assert (sr_fd);

	if (sr_fd->srf_flags & SFF_BUSY)
		ip_panic(("close on busy channel"));

	assert (!(sr_fd->srf_flags & SFF_MINOR));
	(*sr_fd->srf_close)(sr_fd->srf_fd);
#if DEBUG & 256
 { where(); printf("srf_close: 0x%x(%d)\n", sr_fd->srf_close, sr_fd->srf_fd); }
#endif
	sr_fd->srf_flags= SFF_FREE;
}

PRIVATE int sr_rwio(m)
mq_t *m;
{
	sr_fd_t *sr_fd;
	mq_t **q_head_ptr, **q_tail_ptr;
	int ip_flag, susp_flag;
	int result;
	unsigned long request;
	size_t size;

	sr_fd= sr_getchannel(m->mq_mess.DEVICE);
assert (sr_fd);

	switch(m->mq_mess.m_type)
	{
	case NW_READ:
		q_head_ptr= &sr_fd->srf_read_q;
		q_tail_ptr= &sr_fd->srf_read_q_tail;
		ip_flag= SFF_READ_IP;
		susp_flag= SFF_READ_SUSP;
		break;
	case NW_WRITE:
		q_head_ptr= &sr_fd->srf_write_q;
		q_tail_ptr= &sr_fd->srf_write_q_tail;
		ip_flag= SFF_WRITE_IP;
		susp_flag= SFF_WRITE_SUSP;
		break;
	case NW_IOCTL:
		q_head_ptr= &sr_fd->srf_ioctl_q;
		q_tail_ptr= &sr_fd->srf_ioctl_q_tail;
		ip_flag= SFF_IOCTL_IP;
		susp_flag= SFF_IOCTL_SUSP;
		break;
	default:
		ip_panic(("illegal case entry"));
	}

	if (sr_fd->srf_flags & ip_flag)
	{
assert(sr_fd->srf_flags & susp_flag);
assert(*q_head_ptr);
		(*q_tail_ptr)->mq_next= m;
		*q_tail_ptr= m;
		return SUSPEND;
	}
assert(!*q_head_ptr);

	*q_tail_ptr= *q_head_ptr= m;
	sr_fd->srf_flags |= ip_flag;

	switch(m->mq_mess.m_type)
	{
	case NW_READ:
#if DEBUG&256
 { where(); printf("calling 0x%x(%d, %d)\n", sr_fd->srf_read, sr_fd->srf_fd,
	m->mq_mess.COUNT); }
#endif
		result= (*sr_fd->srf_read)(sr_fd->srf_fd, m->mq_mess.COUNT);
		break;
	case NW_WRITE:
#if DEBUG&256
 { where(); printf("calling 0x%x(%d, %d)\n", sr_fd->srf_write, sr_fd->srf_fd,
	m->mq_mess.COUNT); }
#endif
		result= (*sr_fd->srf_write)(sr_fd->srf_fd, m->mq_mess.COUNT);
		break;
	case NW_IOCTL:
		request= m->mq_mess.REQUEST;
#ifdef IOCPARM_MASK
		size= (request >> 16) & IOCPARM_MASK;
		if (size>MAX_IOCTL_S)
		{
#if DEBUG
 { where(); printf("replying EINVAL\n"); }
#endif
			result= sr_put_userdata(sr_fd-sr_fd_table, EINVAL, 
								NULL, 1);
assert(result == OK);
			return OK;
		}
#endif /* IOCPARM_MASK */
#if DEBUG
 { where(); printf("calling 0x%x(%d, 0x%lx)\n", sr_fd->srf_ioctl, sr_fd->srf_fd,
	request); }
#endif
		result=(*sr_fd->srf_ioctl)(sr_fd->srf_fd, request);
		break;
	default:
		ip_panic(("illegal case entry"));
	}

#if DEBUG
 if (result != OK && result != SUSPEND)
 { where(); printf("result= %d\n", result); }
#endif
assert(result == OK || result == SUSPEND);
	if (result == SUSPEND)
		sr_fd->srf_flags |= susp_flag;
	return result;
}

PRIVATE int sr_cancel(m)
message *m;
{
	sr_fd_t *sr_fd;
	int i, result;
	mq_t *q_ptr, *q_ptr_prv;
	int proc_nr;

        result=EINTR;
	proc_nr=  m->PROC_NR;
	sr_fd= sr_getchannel(m->DEVICE);
assert (sr_fd);

	result= walk_queue(sr_fd, sr_fd->srf_ioctl_q, &sr_fd->srf_ioctl_q_tail, 
		SR_CANCEL_IOCTL, proc_nr);
	if (result != EAGAIN)
		return result;
	result= walk_queue(sr_fd, sr_fd->srf_read_q, &sr_fd->srf_read_q_tail, 
		SR_CANCEL_READ, proc_nr);
	if (result != EAGAIN)
		return result;
	result= walk_queue(sr_fd, sr_fd->srf_write_q, &sr_fd->srf_write_q_tail, 
		SR_CANCEL_WRITE, proc_nr);
	if (result != EAGAIN)
		return result;
	ip_panic(("request not found"));
}

PRIVATE int walk_queue(sr_fd, q_head, q_tail_ptr, type, proc_nr)
sr_fd_t *sr_fd;
mq_t *q_head, **q_tail_ptr;
int type;
int proc_nr;
{
	mq_t *q_ptr_prv, *q_ptr;
	int result;

	for(q_ptr_prv= NULL, q_ptr= q_head; q_ptr; 
		q_ptr_prv= q_ptr, q_ptr= q_ptr->mq_next)
	{
		if (q_ptr->mq_mess.PROC_NR != proc_nr)
			continue;
		if (!q_ptr_prv)
		{
#if DEBUG & 256
 { where(); printf("calling 0x%x(%d, %d)\n", sr_fd->srf_cancel, sr_fd->srf_fd,
	type); }
#endif

			result= (*sr_fd->srf_cancel)(sr_fd->srf_fd, type);
assert(result == OK);
			return OK;
		}
		q_ptr_prv->mq_next= q_ptr->mq_next;
		mq_free(q_ptr);
		if (!q_ptr_prv->mq_next)
			*q_tail_ptr= q_ptr_prv;
		return EINTR;
	}
	return EAGAIN;
}

PRIVATE sr_fd_t *sr_getchannel(minor)
int minor;
{
	sr_fd_t *loc_fd;

compare(minor, >=, 0);
compare(minor, <, FD_NR);

	loc_fd= &sr_fd_table[minor];

#if DEBUG
 if ((loc_fd->srf_flags & SFF_MINOR) || !(loc_fd->srf_flags & SFF_INUSE))
 { where(); printf("got req for ill minor (= %d)\n", minor); }
#endif
assert (!(loc_fd->srf_flags & SFF_MINOR) && (loc_fd->srf_flags & SFF_INUSE));

	return loc_fd;
}

PRIVATE void sr_reply (mess_ptr, status)
message *mess_ptr;
int status;
{
	static message reply;
	int result;

#if DEBUG & 256
 { where(); printf("replying %d to %d for proc %d\n", status, 
	mess_ptr->m_source, mess_ptr->PROC_NR); }
#endif
	reply.m_type= REVIVE;	/* There no use for TASK_REPLY */
	reply.REP_PROC_NR= mess_ptr->PROC_NR;
	reply.REP_STATUS= status;
#if DEBUG & 256
 { where(); printf("sending %d to %d for %d\n", reply.m_type,
	mess_ptr->m_source, reply.REP_PROC_NR); }
#endif
assert(mess_ptr->m_source != MM_PROC_NR);
	result= send (mess_ptr->m_source, &reply);
	if (result != OK)
		ip_panic(("unable to send"));
}

PRIVATE acc_t *sr_get_userdata (fd, offset, count, for_ioctl)
int fd;
vir_bytes offset;
vir_bytes count;
int for_ioctl;
{
	sr_fd_t *loc_fd;
	mq_t **head_ptr, **tail_ptr, *m, *tail, *mq;
	int ip_flag, susp_flag;
	int result;
	int suspended;
	char *src;
	acc_t *acc;

#if DEBUG & 256
 { where(); printf("sr_get_userdata(%d, %u, %u, %d)\n",
	fd, offset, count, for_ioctl); }
#endif
	loc_fd= &sr_fd_table[fd];

	if (for_ioctl)
	{
		head_ptr= &loc_fd->srf_ioctl_q;
		tail_ptr= &loc_fd->srf_ioctl_q_tail;
		ip_flag= SFF_IOCTL_IP;
		susp_flag= SFF_IOCTL_SUSP;
	}
	else
	{
		head_ptr= &loc_fd->srf_write_q;
		tail_ptr= &loc_fd->srf_write_q_tail;
		ip_flag= SFF_WRITE_IP;
		susp_flag= SFF_WRITE_SUSP;
	}
		
assert (loc_fd->srf_flags & ip_flag);

	if (!count)
	{
		m= *head_ptr;
		*head_ptr= NULL;
		tail= *tail_ptr;
assert(m);
		mq= m->mq_next;
		result= (int)offset;
		sr_revive (m, result);
		suspended= (loc_fd->srf_flags & susp_flag);
		loc_fd->srf_flags &= ~(ip_flag|susp_flag);
		if (suspended)
		{
			process_req_q(mq, tail, tail_ptr);
		}
		else
		{
assert(!mq);
		}
		return NULL;
	}

	src= (*head_ptr)->mq_mess.ADDRESS + offset;
	result= cp_u2b ((*head_ptr)->mq_mess.PROC_NR, src, &acc, count);

	return result<0 ? NULL : acc;
}

PRIVATE int sr_put_userdata (fd, offset, data, for_ioctl)
int fd;
vir_bytes offset;
acc_t *data;
int for_ioctl;
{
	sr_fd_t *loc_fd;
	mq_t **head_ptr, **tail_ptr, *m, *tail, *mq;
	int ip_flag, susp_flag;
	int result;
	int suspended;
	char *dst;

#if DEBUG & 256
 { where(); printf("sr_put_userdata(%d, %u, 0x%x, %d)\n",
	fd, offset, data, for_ioctl); }
#endif

	loc_fd= &sr_fd_table[fd];

	if (for_ioctl)
	{
		head_ptr= &loc_fd->srf_ioctl_q;
		tail_ptr= &loc_fd->srf_ioctl_q_tail;
		ip_flag= SFF_IOCTL_IP;
		susp_flag= SFF_IOCTL_SUSP;
	}
	else
	{
		head_ptr= &loc_fd->srf_read_q;
		tail_ptr= &loc_fd->srf_read_q_tail;
		ip_flag= SFF_READ_IP;
		susp_flag= SFF_READ_SUSP;
	}
		
assert (loc_fd->srf_flags & ip_flag);

	if (!data)
	{
		m= *head_ptr;
		*head_ptr= NULL;
		tail= *tail_ptr;
assert(m);
		mq= m->mq_next;
		result= (int)offset;
		sr_revive (m, result);
		suspended= (loc_fd->srf_flags & susp_flag);
		loc_fd->srf_flags &= ~(ip_flag|susp_flag);
		if (suspended)
		{
			process_req_q(mq, tail, tail_ptr);
		}
		else
		{
assert(!mq);
		}
		return OK;
	}

	dst= (*head_ptr)->mq_mess.ADDRESS + offset;
	return cp_b2u (data, (*head_ptr)->mq_mess.PROC_NR, dst);
}

PRIVATE void sr_revive (m, status)
mq_t *m;
int status;
{
	static message reply;
	int result;

#if DEBUG & 256
 { where(); printf("sr_revive: replying %d to %d for proc %d\n", status,
	m->mq_mess.m_source, m->mq_mess.PROC_NR); }
#endif
	reply.m_type= REVIVE;
	reply.REP_PROC_NR= m->mq_mess.PROC_NR;
	reply.REP_STATUS= status;
#if DEBUG & 256
 { where(); printf("sending %d to %d for %d\n", reply.m_type,
   m->mq_mess.m_source, reply.REP_PROC_NR); }
#endif
assert(m->mq_mess.m_source != MM_PROC_NR);
	result= send (m->mq_mess.m_source, &reply);
	if (result<0)
	{
		if (result == ELOCKED)
		{
#if DEBUG
 { where(); printf("send locked\n"); }
#endif
			reply.m_source= m->mq_mess.m_source;
			m->mq_mess= reply;
			if (repl_queue)
				repl_queue_tail->mq_next= m;
			else
				repl_queue= m;
			repl_queue_tail= m;
			return;
		}
	else
		ip_panic(("unable to send"));
	}
	mq_free(m);
}

PRIVATE void process_req_q(mq, tail, tail_ptr)
mq_t *mq, *tail, **tail_ptr;
{
	mq_t *m;
	int result;

	for(;mq;)
	{
		m= mq;
		mq= mq->mq_next;

#if DEBUG
 { where(); printf("calling rwio\n"); }
#endif
		result= sr_rwio(m);
		if (result == SUSPEND)
		{
			if (mq)
			{
				(*tail_ptr)->mq_next= mq;
				*tail_ptr= tail;
			}
			return;
		}
	}
	return;
}

PRIVATE int cp_u2b (proc, src, var_acc_ptr, size)
int proc;
char *src;
acc_t **var_acc_ptr;
int size;
{
	static message mess;
	acc_t *acc;
	int i;

	acc= bf_memreq(size);
	*var_acc_ptr= acc;
	i=0;

	while (acc)
	{
		size= (vir_bytes)acc->acc_length;

		cpvec[i].cpv_src= (vir_bytes)src;
		cpvec[i].cpv_dst= (vir_bytes)ptr2acc_data(acc);
		cpvec[i].cpv_size= size;

		src += size;
		acc= acc->acc_next;
		i++;

		if (i == CPVEC_NR)
		{
			mess.m_type= SYS_VCOPY;
			mess.m1_i1= proc;
			mess.m1_i2= THIS_PROC;
			mess.m1_i3= i;
			mess.m1_p1= (char *)cpvec;
			if (sendrec(SYSTASK, &mess) <0)
				ip_panic(("unable to sendrec"));
			if (mess.m_type <0)
			{
				bf_afree(*var_acc_ptr);
				*var_acc_ptr= 0;
				return mess.m_type;
			}
			i= 0;
		}
	}
	if (i)
	{
		mess.m_type= SYS_VCOPY;
		mess.m1_i1= proc;
		mess.m1_i2= THIS_PROC;
		mess.m1_i3= i;
		mess.m1_p1= (char *)cpvec;
		if (sendrec(SYSTASK, &mess) <0)
			ip_panic(("unable to sendrec"));
		if (mess.m_type <0)
		{
			bf_afree(*var_acc_ptr);
			*var_acc_ptr= 0;
			return mess.m_type;
		}
	}
	return OK;
}

PRIVATE int cp_b2u (acc_ptr, proc, dest)
acc_t *acc_ptr;
int proc;
char *dest;
{
	static message mess;
	acc_t *acc;
	int i, size;

	acc= acc_ptr;
	i=0;

	while (acc)
	{
		size= (vir_bytes)acc->acc_length;

		if (size)
		{
			cpvec[i].cpv_src= (vir_bytes)ptr2acc_data(acc);
			cpvec[i].cpv_dst= (vir_bytes)dest;
			cpvec[i].cpv_size= size;
			i++;
		}

		dest += size;
		acc= acc->acc_next;

		if (i == CPVEC_NR)
		{
			mess.m_type= SYS_VCOPY;
			mess.m1_i1= THIS_PROC;
			mess.m1_i2= proc;
			mess.m1_i3= i;
			mess.m1_p1= (char *)cpvec;
			if (sendrec(SYSTASK, &mess) <0)
				ip_panic(("unable to sendrec"));
			if (mess.m_type <0)
			{
				bf_afree(acc_ptr);
				return mess.m_type;
			}
			i= 0;
		}
	}
	if (i)
	{
		mess.m_type= SYS_VCOPY;
		mess.m1_i1= THIS_PROC;
		mess.m1_i2= proc;
		mess.m1_i3= i;
		mess.m1_p1= (char *)cpvec;
		if (sendrec(SYSTASK, &mess) <0)
			ip_panic(("unable to sendrec"));
		if (mess.m_type <0)
		{
			bf_afree(acc_ptr);
			return mess.m_type;
		}
	}
	bf_afree(acc_ptr);
	return OK;
}

PRIVATE int sr_repl_queue(proc)
int proc;
{
	mq_t *m, *m_cancel, *tmp;
	int result;

	m_cancel= NULL;

	for (m= repl_queue; m;)
	{
		if (m->mq_mess.REP_PROC_NR == proc)
		{
assert(!m_cancel);
			m_cancel= m;
			m= m->mq_next;
			continue;
		}
assert(m->mq_mess.m_source != MM_PROC_NR);
		result= send(m->mq_mess.m_source, &m->mq_mess);
		if (result != OK)
			ip_panic(("unable to send: %d", result));
		tmp= m;
		m= m->mq_next;
		mq_free(tmp);
	}
	repl_queue= NULL;
	if (m_cancel)
	{
assert(m_cancel->mq_mess.m_source != MM_PROC_NR);
		result= send(m_cancel->mq_mess.m_source, &m_cancel->mq_mess);
		if (result != OK)
			ip_panic(("unable to send: %d", result));
		mq_free(m_cancel);
		return 1;
	}
	return 0;
}