V8/usr/sys/chaosld/chpacket.c
/*
* C H P A C K E T
*
* Packet handling utilities for the Chaosnet line discipline.
*
*
* (c) Copyright 1985 Nirvonics, Inc.
*
* Written by Kurt Gollhardt
* Last update Thu Feb 28 14:44:14 1985
*
* This software is the property of Nirvonics, Inc.
* All rights reserved.
*
*/
#include "ch.h"
#if NCH > 0
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/stream.h"
#include "../h/conf.h"
#include "../chaosld/types.h"
#include "../chaosld/constants.h"
#include "../chaosld/globals.h"
#define CAREFUL
/*
* Get blocks from a queue, up to the next delimiter,
* and place them into a packet structure.
*/
struct packet *get_packet(q, wflag)
register struct queue *q;
{
register struct packet *pk;
register struct block *bp, **nextbp;
register int len;
len = wflag? 1 : sizeof(struct pkt_header);
if ((bp = getq(q)) == NOBLOCK)
return NOPKT;
#ifdef CAREFUL
if (bp->type != M_DATA ||
bp->wptr - bp->rptr < len) {
freeb(bp);
printf("bad block in get_packet()\n");
return NOPKT;
}
#endif CAREFUL
if ((pk = pkalloc()) == NOPKT) {
freeb(bp);
flush_packet(q);
return NOPKT;
}
if (wflag)
pk->pk_op = *bp->rptr++;
else {
pk->ph = *(struct pkt_header *)(bp->rptr);
bp->rptr += sizeof(struct pkt_header);
}
if (bp->rptr >= bp->wptr) {
freeb(bp);
bp = getq(q);
}
pk->pk_lenword = 0;
nextbp = &pk->data;
while (bp != NOBLOCK && bp->type != M_DELIM) {
pk->pk_lenword += bp->wptr - bp->rptr;
*nextbp = bp;
nextbp = &bp->next;
bp = getq(q);
}
*nextbp = NOBLOCK;
if (bp != NOBLOCK)
freeb(bp); /* Throw away the delimiter */
pk->time = Chclock;
pk->next = NOPKT;
return pk;
}
/*
* Take the header and data blocks from a packet
* and put them onto the queue.
* Any storage associated with the packet is freed.
*/
put_packet(q, pk)
struct queue *q;
struct packet *pk;
{
putcpy(q->next, &pk->ph, sizeof(struct pkt_header));
put_pkdata(q, pk);
}
/*
* Take the data blocks from a packet
* and put them onto the queue.
* Any storage associated with the packet is freed.
*/
put_pkdata(q, pk)
register struct queue *q;
register struct packet *pk;
{
register struct block *bp, *nextb;
for (bp = pk->data; bp != NOBLOCK; bp = nextb) {
nextb = bp->next;
(*q->next->qinfo->putp) (q->next, bp);
}
if (q->flag & QDELIM)
putctl(q->next, M_DELIM);
pk->data = NOBLOCK;
free_packet(pk);
}
/*
* Copy the header and data blocks from a packet onto a queue.
*/
copy_packet(q, pk)
struct queue *q;
struct packet *pk;
{
putcpy(q->next, &pk->ph, sizeof(struct pkt_header));
copy_pkdata(q, pk);
}
/*
* Copy the data blocks from a packet onto a queue.
*/
copy_pkdata(q, pk)
register struct queue *q;
register struct packet *pk;
{
register struct block *bp;
for (bp = pk->data; bp != NOBLOCK; bp = bp->next)
putcpy(q->next, bp->rptr, bp->wptr - bp->rptr);
putctl(q->next, M_DELIM);
}
/*
* Obtain storage for a packet and perfrom minimal initialization.
*/
struct packet *
new_packet()
{
register struct packet *pk;
if ((pk = pkalloc()) == NOPKT)
return NOPKT;
bfill(pk, sizeof(struct packet), 0);
pk->time = Chclock;
return pk;
}
/*
* Release all storage associated with a packet structure.
*/
free_packet(pk)
register struct packet *pk;
{
free_pkdata(pk);
pkfree(pk);
}
/*
* Release all data blocks in packet.
*/
free_pkdata(pk)
register struct packet *pk;
{
register struct block *bp, *nextb;
for (bp = pk->data; bp != NOBLOCK; bp = nextb) {
nextb = bp->next;
freeb(bp);
}
pk->data = NOBLOCK;
pk->pk_lenword = 0;
}
/*
* Collapse all of the data blocks for a packet
* into a single block if possible
*/
flatten(pk)
register struct packet *pk;
{
register struct block *bp, *bigb, *nextb;
register int n;
int ps;
debug(DPKT,printf("flatten packet of length %d\n", pk->pk_len));
if (pk->data->wptr - pk->data->rptr >= pk->pk_len)
return 0;
if ((bigb = allocb(pk->pk_len)) == NOBLOCK) {
debug(DPKT|DABNOR,printf("flatten: can't alloc block\n"));
return -1;
}
bigb->next = NOBLOCK;
bp = pk->data;
ps = spl6();
pk->data = bigb;
while (bp != NOBLOCK) {
n = bp->wptr - bp->rptr;
if (bigb->lim - bigb->wptr < n)
n = bigb->lim - bigb->wptr;
bcopy(bp->rptr, bigb->wptr, n);
bigb->wptr += n;
bp->rptr += n;
if (bp->rptr < bp->wptr) {
bigb->next = bp;
splx(ps);
debug(DPKT|DABNOR,printf("flatten: not enough room in block\n"));
return -1;
}
nextb = bp->next;
freeb(bp);
bp = nextb;
}
splx(ps);
return 0;
}
/*
* Add some bytes of data to the end of a packet.
* Allocate blocks as necessary.
*/
append_packet(pkt, buf, n)
register struct packet *pkt;
char *buf;
int n;
{
register struct block *bp;
register int nmin;
if (pkt->data == NOBLOCK) {
if ((bp = allocb(n)) == NOBLOCK)
return;
pkt->data = bp;
bp->next = NOBLOCK;
} else {
for (bp = pkt->data; bp->next != NOBLOCK; bp = bp->next)
;
}
while (n > 0) {
if (bp->wptr == bp->lim) {
if ((bp->next = allocb(n)) == NOBLOCK)
return;
bp = bp->next;
bp->next = NOBLOCK;
}
nmin = bp->lim - bp->wptr;
if (nmin > n)
nmin = n;
bcopy(buf, bp->wptr, nmin);
buf += nmin;
bp->wptr += nmin;
pkt->pk_lenword += nmin;
n -= nmin;
}
}
/*
* Free a list of packets
*/
freelist(pkt)
register struct packet *pkt;
{
register struct packet *opkt;
while ((opkt = pkt) != NOPKT) {
pkt = pkt->next;
free_packet(opkt);
}
}