xref: /plan9/sys/src/9/ip/rudp.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
17dd7cddfSDavid du Colombier /*
2d5099b52SDavid du Colombier  *  Reliable User Datagram Protocol, currently only for IPv4.
37dd7cddfSDavid du Colombier  *  This protocol is compatible with UDP's packet format.
47dd7cddfSDavid du Colombier  *  It could be done over UDP if need be.
57dd7cddfSDavid du Colombier  */
67dd7cddfSDavid du Colombier #include	"u.h"
77dd7cddfSDavid du Colombier #include	"../port/lib.h"
87dd7cddfSDavid du Colombier #include	"mem.h"
97dd7cddfSDavid du Colombier #include	"dat.h"
107dd7cddfSDavid du Colombier #include	"fns.h"
117dd7cddfSDavid du Colombier #include	"../port/error.h"
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier #include	"ip.h"
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier #define DEBUG	0
167dd7cddfSDavid du Colombier #define DPRINT if(DEBUG)print
177dd7cddfSDavid du Colombier 
187dd7cddfSDavid du Colombier #define SEQDIFF(a,b) ( (a)>=(b)?\
197dd7cddfSDavid du Colombier 			(a)-(b):\
207dd7cddfSDavid du Colombier 			0xffffffffUL-((b)-(a)) )
217dd7cddfSDavid du Colombier #define INSEQ(a,start,end) ( (start)<=(end)?\
227dd7cddfSDavid du Colombier 				((a)>(start)&&(a)<=(end)):\
237dd7cddfSDavid du Colombier 				((a)>(start)||(a)<=(end)) )
247dd7cddfSDavid du Colombier #define UNACKED(r) SEQDIFF(r->sndseq, r->ackrcvd)
257dd7cddfSDavid du Colombier #define NEXTSEQ(a) ( (a)+1 == 0 ? 1 : (a)+1 )
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier enum
287dd7cddfSDavid du Colombier {
297dd7cddfSDavid du Colombier 	UDP_PHDRSIZE	= 12,	/* pseudo header */
3084363d68SDavid du Colombier //	UDP_HDRSIZE	= 20,	/* pseudo header + udp header */
317dd7cddfSDavid du Colombier 	UDP_RHDRSIZE	= 36,	/* pseudo header + udp header + rudp header */
327dd7cddfSDavid du Colombier 	UDP_IPHDR	= 8,	/* ip header */
337dd7cddfSDavid du Colombier 	IP_UDPPROTO	= 254,
3484363d68SDavid du Colombier 	UDP_USEAD7	= 52,	/* size of new ipv6 headers struct */
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier 	Rudprxms	= 200,
377dd7cddfSDavid du Colombier 	Rudptickms	= 50,
387dd7cddfSDavid du Colombier 	Rudpmaxxmit	= 10,
397dd7cddfSDavid du Colombier 	Maxunacked	= 100,
407dd7cddfSDavid du Colombier };
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier #define Hangupgen	0xffffffff	/* used only in hangup messages */
437dd7cddfSDavid du Colombier 
447dd7cddfSDavid du Colombier typedef struct Udphdr Udphdr;
457dd7cddfSDavid du Colombier struct Udphdr
467dd7cddfSDavid du Colombier {
477dd7cddfSDavid du Colombier 	/* ip header */
487dd7cddfSDavid du Colombier 	uchar	vihl;		/* Version and header length */
497dd7cddfSDavid du Colombier 	uchar	tos;		/* Type of service */
507dd7cddfSDavid du Colombier 	uchar	length[2];	/* packet length */
517dd7cddfSDavid du Colombier 	uchar	id[2];		/* Identification */
527dd7cddfSDavid du Colombier 	uchar	frag[2];	/* Fragment information */
537dd7cddfSDavid du Colombier 
547dd7cddfSDavid du Colombier 	/* pseudo header starts here */
557dd7cddfSDavid du Colombier 	uchar	Unused;
567dd7cddfSDavid du Colombier 	uchar	udpproto;	/* Protocol */
577dd7cddfSDavid du Colombier 	uchar	udpplen[2];	/* Header plus data length */
587dd7cddfSDavid du Colombier 	uchar	udpsrc[4];	/* Ip source */
597dd7cddfSDavid du Colombier 	uchar	udpdst[4];	/* Ip destination */
607dd7cddfSDavid du Colombier 
617dd7cddfSDavid du Colombier 	/* udp header */
627dd7cddfSDavid du Colombier 	uchar	udpsport[2];	/* Source port */
637dd7cddfSDavid du Colombier 	uchar	udpdport[2];	/* Destination port */
647dd7cddfSDavid du Colombier 	uchar	udplen[2];	/* data length */
657dd7cddfSDavid du Colombier 	uchar	udpcksum[2];	/* Checksum */
667dd7cddfSDavid du Colombier };
677dd7cddfSDavid du Colombier 
687dd7cddfSDavid du Colombier typedef struct Rudphdr Rudphdr;
697dd7cddfSDavid du Colombier struct Rudphdr
707dd7cddfSDavid du Colombier {
717dd7cddfSDavid du Colombier 	/* ip header */
727dd7cddfSDavid du Colombier 	uchar	vihl;		/* Version and header length */
737dd7cddfSDavid du Colombier 	uchar	tos;		/* Type of service */
747dd7cddfSDavid du Colombier 	uchar	length[2];	/* packet length */
757dd7cddfSDavid du Colombier 	uchar	id[2];		/* Identification */
767dd7cddfSDavid du Colombier 	uchar	frag[2];	/* Fragment information */
777dd7cddfSDavid du Colombier 
787dd7cddfSDavid du Colombier 	/* pseudo header starts here */
797dd7cddfSDavid du Colombier 	uchar	Unused;
807dd7cddfSDavid du Colombier 	uchar	udpproto;	/* Protocol */
817dd7cddfSDavid du Colombier 	uchar	udpplen[2];	/* Header plus data length */
827dd7cddfSDavid du Colombier 	uchar	udpsrc[4];	/* Ip source */
837dd7cddfSDavid du Colombier 	uchar	udpdst[4];	/* Ip destination */
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier 	/* udp header */
867dd7cddfSDavid du Colombier 	uchar	udpsport[2];	/* Source port */
877dd7cddfSDavid du Colombier 	uchar	udpdport[2];	/* Destination port */
887dd7cddfSDavid du Colombier 	uchar	udplen[2];	/* data length (includes rudp header) */
897dd7cddfSDavid du Colombier 	uchar	udpcksum[2];	/* Checksum */
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier 	/* rudp header */
927dd7cddfSDavid du Colombier 	uchar	relseq[4];	/* id of this packet (or 0) */
937dd7cddfSDavid du Colombier 	uchar	relsgen[4];	/* generation/time stamp */
947dd7cddfSDavid du Colombier 	uchar	relack[4];	/* packet being acked (or 0) */
957dd7cddfSDavid du Colombier 	uchar	relagen[4];	/* generation/time stamp */
967dd7cddfSDavid du Colombier };
977dd7cddfSDavid du Colombier 
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier /*
1007dd7cddfSDavid du Colombier  *  one state structure per destination
1017dd7cddfSDavid du Colombier  */
1027dd7cddfSDavid du Colombier typedef struct Reliable Reliable;
1037dd7cddfSDavid du Colombier struct Reliable
1047dd7cddfSDavid du Colombier {
1057dd7cddfSDavid du Colombier 	Ref;
1067dd7cddfSDavid du Colombier 
1077dd7cddfSDavid du Colombier 	Reliable *next;
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier 	uchar	addr[IPaddrlen];	/* always V6 when put here */
1107dd7cddfSDavid du Colombier 	ushort	port;
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier 	Block	*unacked;	/* unacked msg list */
1137dd7cddfSDavid du Colombier 	Block	*unackedtail;	/*  and its tail */
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier 	int	timeout;	/* time since first unacked msg sent */
1167dd7cddfSDavid du Colombier 	int	xmits;		/* number of times first unacked msg sent */
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier 	ulong	sndseq;		/* next packet to be sent */
1197dd7cddfSDavid du Colombier 	ulong	sndgen;		/*  and its generation */
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier 	ulong	rcvseq;		/* last packet received */
1227dd7cddfSDavid du Colombier 	ulong	rcvgen;		/*  and its generation */
1237dd7cddfSDavid du Colombier 
1247dd7cddfSDavid du Colombier 	ulong	acksent;	/* last ack sent */
1257dd7cddfSDavid du Colombier 	ulong	ackrcvd;	/* last msg for which ack was rcvd */
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier 	/* flow control */
1287dd7cddfSDavid du Colombier 	QLock	lock;
1297dd7cddfSDavid du Colombier 	Rendez	vous;
1307dd7cddfSDavid du Colombier 	int	blocked;
1317dd7cddfSDavid du Colombier };
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier 
1347dd7cddfSDavid du Colombier 
1357dd7cddfSDavid du Colombier /* MIB II counters */
1367dd7cddfSDavid du Colombier typedef struct Rudpstats Rudpstats;
1377dd7cddfSDavid du Colombier struct Rudpstats
1387dd7cddfSDavid du Colombier {
1397dd7cddfSDavid du Colombier 	ulong	rudpInDatagrams;
1407dd7cddfSDavid du Colombier 	ulong	rudpNoPorts;
1417dd7cddfSDavid du Colombier 	ulong	rudpInErrors;
1427dd7cddfSDavid du Colombier 	ulong	rudpOutDatagrams;
1437dd7cddfSDavid du Colombier };
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier typedef struct Rudppriv Rudppriv;
1467dd7cddfSDavid du Colombier struct Rudppriv
1477dd7cddfSDavid du Colombier {
14880ee5cbfSDavid du Colombier 	Ipht	ht;
1497dd7cddfSDavid du Colombier 
1507dd7cddfSDavid du Colombier 	/* MIB counters */
1517dd7cddfSDavid du Colombier 	Rudpstats	ustats;
1527dd7cddfSDavid du Colombier 
1537dd7cddfSDavid du Colombier 	/* non-MIB stats */
1547dd7cddfSDavid du Colombier 	ulong	csumerr;		/* checksum errors */
1557dd7cddfSDavid du Colombier 	ulong	lenerr;			/* short packet */
1567dd7cddfSDavid du Colombier 	ulong	rxmits;			/* # of retransmissions */
1577dd7cddfSDavid du Colombier 	ulong	orders;			/* # of out of order pkts */
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier 	/* keeping track of the ack kproc */
1607dd7cddfSDavid du Colombier 	int	ackprocstarted;
1617dd7cddfSDavid du Colombier 	QLock	apl;
1627dd7cddfSDavid du Colombier };
1637dd7cddfSDavid du Colombier 
1647dd7cddfSDavid du Colombier 
1657dd7cddfSDavid du Colombier static ulong generation = 0;
1667dd7cddfSDavid du Colombier static Rendez rend;
1677dd7cddfSDavid du Colombier 
1687dd7cddfSDavid du Colombier /*
1697dd7cddfSDavid du Colombier  *  protocol specific part of Conv
1707dd7cddfSDavid du Colombier  */
1717dd7cddfSDavid du Colombier typedef struct Rudpcb Rudpcb;
1727dd7cddfSDavid du Colombier struct Rudpcb
1737dd7cddfSDavid du Colombier {
1747dd7cddfSDavid du Colombier 	QLock;
1757dd7cddfSDavid du Colombier 	uchar	headers;
1767dd7cddfSDavid du Colombier 	uchar	randdrop;
1777dd7cddfSDavid du Colombier 	Reliable *r;
1787dd7cddfSDavid du Colombier };
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier /*
1817dd7cddfSDavid du Colombier  * local functions
1827dd7cddfSDavid du Colombier  */
1837dd7cddfSDavid du Colombier void	relsendack(Conv*, Reliable*, int);
1847dd7cddfSDavid du Colombier int	reliput(Conv*, Block*, uchar*, ushort);
1857dd7cddfSDavid du Colombier Reliable *relstate(Rudpcb*, uchar*, ushort, char*);
1867dd7cddfSDavid du Colombier void	relput(Reliable*);
1877dd7cddfSDavid du Colombier void	relforget(Conv *, uchar*, int, int);
1887dd7cddfSDavid du Colombier void	relackproc(void *);
1897dd7cddfSDavid du Colombier void	relackq(Reliable *, Block*);
1907dd7cddfSDavid du Colombier void	relhangup(Conv *, Reliable*);
1917dd7cddfSDavid du Colombier void	relrexmit(Conv *, Reliable*);
1927dd7cddfSDavid du Colombier void	relput(Reliable*);
1933ff48bf5SDavid du Colombier void	rudpkick(void *x);
1947dd7cddfSDavid du Colombier 
1957dd7cddfSDavid du Colombier static void
rudpstartackproc(Proto * rudp)1967dd7cddfSDavid du Colombier rudpstartackproc(Proto *rudp)
1977dd7cddfSDavid du Colombier {
1987dd7cddfSDavid du Colombier 	Rudppriv *rpriv;
1999a747e4fSDavid du Colombier 	char kpname[KNAMELEN];
2007dd7cddfSDavid du Colombier 
2017dd7cddfSDavid du Colombier 	rpriv = rudp->priv;
2027dd7cddfSDavid du Colombier 	if(rpriv->ackprocstarted == 0){
2037dd7cddfSDavid du Colombier 		qlock(&rpriv->apl);
2047dd7cddfSDavid du Colombier 		if(rpriv->ackprocstarted == 0){
205*4e3613abSDavid du Colombier 			snprint(kpname, sizeof kpname, "#I%drudpack",
206*4e3613abSDavid du Colombier 				rudp->f->dev);
2077dd7cddfSDavid du Colombier 			kproc(kpname, relackproc, rudp);
2087dd7cddfSDavid du Colombier 			rpriv->ackprocstarted = 1;
2097dd7cddfSDavid du Colombier 		}
2107dd7cddfSDavid du Colombier 		qunlock(&rpriv->apl);
2117dd7cddfSDavid du Colombier 	}
2127dd7cddfSDavid du Colombier }
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier static char*
rudpconnect(Conv * c,char ** argv,int argc)2157dd7cddfSDavid du Colombier rudpconnect(Conv *c, char **argv, int argc)
2167dd7cddfSDavid du Colombier {
2177dd7cddfSDavid du Colombier 	char *e;
21880ee5cbfSDavid du Colombier 	Rudppriv *upriv;
2197dd7cddfSDavid du Colombier 
22080ee5cbfSDavid du Colombier 	upriv = c->p->priv;
2217dd7cddfSDavid du Colombier 	rudpstartackproc(c->p);
2227dd7cddfSDavid du Colombier 	e = Fsstdconnect(c, argv, argc);
2237dd7cddfSDavid du Colombier 	Fsconnected(c, e);
22480ee5cbfSDavid du Colombier 	iphtadd(&upriv->ht, c);
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier 	return e;
2277dd7cddfSDavid du Colombier }
2287dd7cddfSDavid du Colombier 
2297dd7cddfSDavid du Colombier 
2307dd7cddfSDavid du Colombier static int
rudpstate(Conv * c,char * state,int n)2317dd7cddfSDavid du Colombier rudpstate(Conv *c, char *state, int n)
2327dd7cddfSDavid du Colombier {
2337dd7cddfSDavid du Colombier 	Rudpcb *ucb;
2347dd7cddfSDavid du Colombier 	Reliable *r;
2357dd7cddfSDavid du Colombier 	int m;
2367dd7cddfSDavid du Colombier 
2377dd7cddfSDavid du Colombier 	m = snprint(state, n, "%s", c->inuse?"Open":"Closed");
2387dd7cddfSDavid du Colombier 	ucb = (Rudpcb*)c->ptcl;
2397dd7cddfSDavid du Colombier 	qlock(ucb);
2407dd7cddfSDavid du Colombier 	for(r = ucb->r; r; r = r->next)
2417dd7cddfSDavid du Colombier 		m += snprint(state+m, n-m, " %I/%ld", r->addr, UNACKED(r));
24203a1fc68SDavid du Colombier 	m += snprint(state+m, n-m, "\n");
2437dd7cddfSDavid du Colombier 	qunlock(ucb);
2447dd7cddfSDavid du Colombier 	return m;
2457dd7cddfSDavid du Colombier }
2467dd7cddfSDavid du Colombier 
2477dd7cddfSDavid du Colombier static char*
rudpannounce(Conv * c,char ** argv,int argc)2487dd7cddfSDavid du Colombier rudpannounce(Conv *c, char** argv, int argc)
2497dd7cddfSDavid du Colombier {
2507dd7cddfSDavid du Colombier 	char *e;
25180ee5cbfSDavid du Colombier 	Rudppriv *upriv;
2527dd7cddfSDavid du Colombier 
25380ee5cbfSDavid du Colombier 	upriv = c->p->priv;
2547dd7cddfSDavid du Colombier 	rudpstartackproc(c->p);
2557dd7cddfSDavid du Colombier 	e = Fsstdannounce(c, argv, argc);
2567dd7cddfSDavid du Colombier 	if(e != nil)
2577dd7cddfSDavid du Colombier 		return e;
2587dd7cddfSDavid du Colombier 	Fsconnected(c, nil);
25980ee5cbfSDavid du Colombier 	iphtadd(&upriv->ht, c);
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier 	return nil;
2627dd7cddfSDavid du Colombier }
2637dd7cddfSDavid du Colombier 
2647dd7cddfSDavid du Colombier static void
rudpcreate(Conv * c)2657dd7cddfSDavid du Colombier rudpcreate(Conv *c)
2667dd7cddfSDavid du Colombier {
2673ff48bf5SDavid du Colombier 	c->rq = qopen(64*1024, Qmsg, 0, 0);
2683ff48bf5SDavid du Colombier 	c->wq = qopen(64*1024, Qkick, rudpkick, c);
2697dd7cddfSDavid du Colombier }
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier static void
rudpclose(Conv * c)2727dd7cddfSDavid du Colombier rudpclose(Conv *c)
2737dd7cddfSDavid du Colombier {
2747dd7cddfSDavid du Colombier 	Rudpcb *ucb;
2757dd7cddfSDavid du Colombier 	Reliable *r, *nr;
27680ee5cbfSDavid du Colombier 	Rudppriv *upriv;
27780ee5cbfSDavid du Colombier 
27880ee5cbfSDavid du Colombier 	upriv = c->p->priv;
27980ee5cbfSDavid du Colombier 	iphtrem(&upriv->ht, c);
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier 	/* force out any delayed acks */
2827dd7cddfSDavid du Colombier 	ucb = (Rudpcb*)c->ptcl;
2837dd7cddfSDavid du Colombier 	qlock(ucb);
2847dd7cddfSDavid du Colombier 	for(r = ucb->r; r; r = r->next){
2857dd7cddfSDavid du Colombier 		if(r->acksent != r->rcvseq)
2867dd7cddfSDavid du Colombier 			relsendack(c, r, 0);
2877dd7cddfSDavid du Colombier 	}
2887dd7cddfSDavid du Colombier 	qunlock(ucb);
2897dd7cddfSDavid du Colombier 
2907dd7cddfSDavid du Colombier 	qclose(c->rq);
2917dd7cddfSDavid du Colombier 	qclose(c->wq);
2927dd7cddfSDavid du Colombier 	qclose(c->eq);
2937dd7cddfSDavid du Colombier 	ipmove(c->laddr, IPnoaddr);
2947dd7cddfSDavid du Colombier 	ipmove(c->raddr, IPnoaddr);
2957dd7cddfSDavid du Colombier 	c->lport = 0;
2967dd7cddfSDavid du Colombier 	c->rport = 0;
2977dd7cddfSDavid du Colombier 
2987dd7cddfSDavid du Colombier 	ucb->headers = 0;
2997dd7cddfSDavid du Colombier 	ucb->randdrop = 0;
3007dd7cddfSDavid du Colombier 	qlock(ucb);
3017dd7cddfSDavid du Colombier 	for(r = ucb->r; r; r = nr){
3027dd7cddfSDavid du Colombier 		if(r->acksent != r->rcvseq)
3037dd7cddfSDavid du Colombier 			relsendack(c, r, 0);
3047dd7cddfSDavid du Colombier 		nr = r->next;
3057dd7cddfSDavid du Colombier 		relhangup(c, r);
3067dd7cddfSDavid du Colombier 		relput(r);
3077dd7cddfSDavid du Colombier 	}
3087dd7cddfSDavid du Colombier 	ucb->r = 0;
3097dd7cddfSDavid du Colombier 
3107dd7cddfSDavid du Colombier 	qunlock(ucb);
3117dd7cddfSDavid du Colombier }
3127dd7cddfSDavid du Colombier 
3137dd7cddfSDavid du Colombier /*
3147dd7cddfSDavid du Colombier  *  randomly don't send packets
3157dd7cddfSDavid du Colombier  */
3167dd7cddfSDavid du Colombier static void
doipoput(Conv * c,Fs * f,Block * bp,int x,int ttl,int tos)3177dd7cddfSDavid du Colombier doipoput(Conv *c, Fs *f, Block *bp, int x, int ttl, int tos)
3187dd7cddfSDavid du Colombier {
3197dd7cddfSDavid du Colombier 	Rudpcb *ucb;
3207dd7cddfSDavid du Colombier 
3217dd7cddfSDavid du Colombier 	ucb = (Rudpcb*)c->ptcl;
3227dd7cddfSDavid du Colombier 	if(ucb->randdrop && nrand(100) < ucb->randdrop)
3237dd7cddfSDavid du Colombier 		freeblist(bp);
3247dd7cddfSDavid du Colombier 	else
325a6a9e072SDavid du Colombier 		ipoput4(f, bp, x, ttl, tos, nil);
3267dd7cddfSDavid du Colombier }
3277dd7cddfSDavid du Colombier 
3287dd7cddfSDavid du Colombier int
flow(void * v)3297dd7cddfSDavid du Colombier flow(void *v)
3307dd7cddfSDavid du Colombier {
3317dd7cddfSDavid du Colombier 	Reliable *r = v;
3327dd7cddfSDavid du Colombier 
3337dd7cddfSDavid du Colombier 	return UNACKED(r) <= Maxunacked;
3347dd7cddfSDavid du Colombier }
3357dd7cddfSDavid du Colombier 
3367dd7cddfSDavid du Colombier void
rudpkick(void * x)3373ff48bf5SDavid du Colombier rudpkick(void *x)
3387dd7cddfSDavid du Colombier {
3393ff48bf5SDavid du Colombier 	Conv *c = x;
3407dd7cddfSDavid du Colombier 	Udphdr *uh;
3417dd7cddfSDavid du Colombier 	ushort rport;
3427dd7cddfSDavid du Colombier 	uchar laddr[IPaddrlen], raddr[IPaddrlen];
3437dd7cddfSDavid du Colombier 	Block *bp;
3447dd7cddfSDavid du Colombier 	Rudpcb *ucb;
3457dd7cddfSDavid du Colombier 	Rudphdr *rh;
3467dd7cddfSDavid du Colombier 	Reliable *r;
3477dd7cddfSDavid du Colombier 	int dlen, ptcllen;
3487dd7cddfSDavid du Colombier 	Rudppriv *upriv;
3497dd7cddfSDavid du Colombier 	Fs *f;
3507dd7cddfSDavid du Colombier 
3517dd7cddfSDavid du Colombier 	upriv = c->p->priv;
3527dd7cddfSDavid du Colombier 	f = c->p->f;
3537dd7cddfSDavid du Colombier 
3547dd7cddfSDavid du Colombier 	netlog(c->p->f, Logrudp, "rudp: kick\n");
3557dd7cddfSDavid du Colombier 	bp = qget(c->wq);
3567dd7cddfSDavid du Colombier 	if(bp == nil)
3577dd7cddfSDavid du Colombier 		return;
3587dd7cddfSDavid du Colombier 
3597dd7cddfSDavid du Colombier 	ucb = (Rudpcb*)c->ptcl;
3607dd7cddfSDavid du Colombier 	switch(ucb->headers) {
361dc5a79c1SDavid du Colombier 	case 7:
362dc5a79c1SDavid du Colombier 		/* get user specified addresses */
363dc5a79c1SDavid du Colombier 		bp = pullupblock(bp, UDP_USEAD7);
364dc5a79c1SDavid du Colombier 		if(bp == nil)
365dc5a79c1SDavid du Colombier 			return;
366dc5a79c1SDavid du Colombier 		ipmove(raddr, bp->rp);
367dc5a79c1SDavid du Colombier 		bp->rp += IPaddrlen;
368dc5a79c1SDavid du Colombier 		ipmove(laddr, bp->rp);
369dc5a79c1SDavid du Colombier 		bp->rp += IPaddrlen;
370dc5a79c1SDavid du Colombier 		/* pick interface closest to dest */
371dc5a79c1SDavid du Colombier 		if(ipforme(f, laddr) != Runi)
372dc5a79c1SDavid du Colombier 			findlocalip(f, laddr, raddr);
373dc5a79c1SDavid du Colombier 		bp->rp += IPaddrlen;		/* Ignore ifc address */
374dc5a79c1SDavid du Colombier 		rport = nhgets(bp->rp);
375dc5a79c1SDavid du Colombier 		bp->rp += 2+2;			/* Ignore local port */
376dc5a79c1SDavid du Colombier 		break;
3777dd7cddfSDavid du Colombier 	default:
3787dd7cddfSDavid du Colombier 		ipmove(raddr, c->raddr);
3797dd7cddfSDavid du Colombier 		ipmove(laddr, c->laddr);
3807dd7cddfSDavid du Colombier 		rport = c->rport;
3817dd7cddfSDavid du Colombier 		break;
3827dd7cddfSDavid du Colombier 	}
3837dd7cddfSDavid du Colombier 
3847dd7cddfSDavid du Colombier 	dlen = blocklen(bp);
3857dd7cddfSDavid du Colombier 
3867dd7cddfSDavid du Colombier 	/* Make space to fit rudp & ip header */
3877dd7cddfSDavid du Colombier 	bp = padblock(bp, UDP_IPHDR+UDP_RHDRSIZE);
3887dd7cddfSDavid du Colombier 	if(bp == nil)
3897dd7cddfSDavid du Colombier 		return;
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier 	uh = (Udphdr *)(bp->rp);
3923ff48bf5SDavid du Colombier 	uh->vihl = IP_VER4;
3937dd7cddfSDavid du Colombier 
3947dd7cddfSDavid du Colombier 	rh = (Rudphdr*)uh;
3957dd7cddfSDavid du Colombier 
3967dd7cddfSDavid du Colombier 	ptcllen = dlen + (UDP_RHDRSIZE-UDP_PHDRSIZE);
3977dd7cddfSDavid du Colombier 	uh->Unused = 0;
3987dd7cddfSDavid du Colombier 	uh->udpproto = IP_UDPPROTO;
3997dd7cddfSDavid du Colombier 	uh->frag[0] = 0;
4007dd7cddfSDavid du Colombier 	uh->frag[1] = 0;
4017dd7cddfSDavid du Colombier 	hnputs(uh->udpplen, ptcllen);
4027dd7cddfSDavid du Colombier 	switch(ucb->headers){
403dc5a79c1SDavid du Colombier 	case 7:
4047dd7cddfSDavid du Colombier 		v6tov4(uh->udpdst, raddr);
4057dd7cddfSDavid du Colombier 		hnputs(uh->udpdport, rport);
4067dd7cddfSDavid du Colombier 		v6tov4(uh->udpsrc, laddr);
4077dd7cddfSDavid du Colombier 		break;
4087dd7cddfSDavid du Colombier 	default:
4097dd7cddfSDavid du Colombier 		v6tov4(uh->udpdst, c->raddr);
4107dd7cddfSDavid du Colombier 		hnputs(uh->udpdport, c->rport);
4117dd7cddfSDavid du Colombier 		if(ipcmp(c->laddr, IPnoaddr) == 0)
4127dd7cddfSDavid du Colombier 			findlocalip(f, c->laddr, c->raddr);
4137dd7cddfSDavid du Colombier 		v6tov4(uh->udpsrc, c->laddr);
4147dd7cddfSDavid du Colombier 		break;
4157dd7cddfSDavid du Colombier 	}
4167dd7cddfSDavid du Colombier 	hnputs(uh->udpsport, c->lport);
4177dd7cddfSDavid du Colombier 	hnputs(uh->udplen, ptcllen);
4187dd7cddfSDavid du Colombier 	uh->udpcksum[0] = 0;
4197dd7cddfSDavid du Colombier 	uh->udpcksum[1] = 0;
4207dd7cddfSDavid du Colombier 
4217dd7cddfSDavid du Colombier 	qlock(ucb);
4227dd7cddfSDavid du Colombier 	r = relstate(ucb, raddr, rport, "kick");
4237dd7cddfSDavid du Colombier 	r->sndseq = NEXTSEQ(r->sndseq);
4247dd7cddfSDavid du Colombier 	hnputl(rh->relseq, r->sndseq);
4257dd7cddfSDavid du Colombier 	hnputl(rh->relsgen, r->sndgen);
4267dd7cddfSDavid du Colombier 
4277dd7cddfSDavid du Colombier 	hnputl(rh->relack, r->rcvseq);  /* ACK last rcvd packet */
4287dd7cddfSDavid du Colombier 	hnputl(rh->relagen, r->rcvgen);
4297dd7cddfSDavid du Colombier 
4307dd7cddfSDavid du Colombier 	if(r->rcvseq != r->acksent)
4317dd7cddfSDavid du Colombier 		r->acksent = r->rcvseq;
4327dd7cddfSDavid du Colombier 
4337dd7cddfSDavid du Colombier 	hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_RHDRSIZE));
4347dd7cddfSDavid du Colombier 
4357dd7cddfSDavid du Colombier 	relackq(r, bp);
4367dd7cddfSDavid du Colombier 	qunlock(ucb);
4377dd7cddfSDavid du Colombier 
4387dd7cddfSDavid du Colombier 	upriv->ustats.rudpOutDatagrams++;
4397dd7cddfSDavid du Colombier 
4407dd7cddfSDavid du Colombier 	DPRINT("sent: %lud/%lud, %lud/%lud\n",
4417dd7cddfSDavid du Colombier 		r->sndseq, r->sndgen, r->rcvseq, r->rcvgen);
4427dd7cddfSDavid du Colombier 
4437dd7cddfSDavid du Colombier 	doipoput(c, f, bp, 0, c->ttl, c->tos);
4447dd7cddfSDavid du Colombier 
4457dd7cddfSDavid du Colombier 	if(waserror()) {
4467dd7cddfSDavid du Colombier 		relput(r);
4477dd7cddfSDavid du Colombier 		qunlock(&r->lock);
4487dd7cddfSDavid du Colombier 		nexterror();
4497dd7cddfSDavid du Colombier 	}
4507dd7cddfSDavid du Colombier 
4517dd7cddfSDavid du Colombier 	/* flow control of sorts */
4527dd7cddfSDavid du Colombier 	qlock(&r->lock);
4537dd7cddfSDavid du Colombier 	if(UNACKED(r) > Maxunacked){
4547dd7cddfSDavid du Colombier 		r->blocked = 1;
4557dd7cddfSDavid du Colombier 		sleep(&r->vous, flow, r);
4567dd7cddfSDavid du Colombier 		r->blocked = 0;
4577dd7cddfSDavid du Colombier 	}
4587dd7cddfSDavid du Colombier 
4597dd7cddfSDavid du Colombier 	qunlock(&r->lock);
4607dd7cddfSDavid du Colombier 	relput(r);
4617dd7cddfSDavid du Colombier 	poperror();
4627dd7cddfSDavid du Colombier }
4637dd7cddfSDavid du Colombier 
4647dd7cddfSDavid du Colombier void
rudpiput(Proto * rudp,Ipifc * ifc,Block * bp)4659a747e4fSDavid du Colombier rudpiput(Proto *rudp, Ipifc *ifc, Block *bp)
4667dd7cddfSDavid du Colombier {
4677dd7cddfSDavid du Colombier 	int len, olen, ottl;
4687dd7cddfSDavid du Colombier 	Udphdr *uh;
46980ee5cbfSDavid du Colombier 	Conv *c;
4707dd7cddfSDavid du Colombier 	Rudpcb *ucb;
4717dd7cddfSDavid du Colombier 	uchar raddr[IPaddrlen], laddr[IPaddrlen];
4727dd7cddfSDavid du Colombier 	ushort rport, lport;
4737dd7cddfSDavid du Colombier 	Rudppriv *upriv;
4747dd7cddfSDavid du Colombier 	Fs *f;
475dc5a79c1SDavid du Colombier 	uchar *p;
4767dd7cddfSDavid du Colombier 
4777dd7cddfSDavid du Colombier 	upriv = rudp->priv;
4787dd7cddfSDavid du Colombier 	f = rudp->f;
4797dd7cddfSDavid du Colombier 
4807dd7cddfSDavid du Colombier 	upriv->ustats.rudpInDatagrams++;
4817dd7cddfSDavid du Colombier 
4827dd7cddfSDavid du Colombier 	uh = (Udphdr*)(bp->rp);
4837dd7cddfSDavid du Colombier 
4847dd7cddfSDavid du Colombier 	/* Put back pseudo header for checksum
4857dd7cddfSDavid du Colombier 	 * (remember old values for icmpnoconv())
4867dd7cddfSDavid du Colombier 	 */
4877dd7cddfSDavid du Colombier 	ottl = uh->Unused;
4887dd7cddfSDavid du Colombier 	uh->Unused = 0;
4897dd7cddfSDavid du Colombier 	len = nhgets(uh->udplen);
4907dd7cddfSDavid du Colombier 	olen = nhgets(uh->udpplen);
4917dd7cddfSDavid du Colombier 	hnputs(uh->udpplen, len);
4927dd7cddfSDavid du Colombier 
4937dd7cddfSDavid du Colombier 	v4tov6(raddr, uh->udpsrc);
4947dd7cddfSDavid du Colombier 	v4tov6(laddr, uh->udpdst);
4957dd7cddfSDavid du Colombier 	lport = nhgets(uh->udpdport);
4967dd7cddfSDavid du Colombier 	rport = nhgets(uh->udpsport);
4977dd7cddfSDavid du Colombier 
4987dd7cddfSDavid du Colombier 	if(nhgets(uh->udpcksum)) {
4997dd7cddfSDavid du Colombier 		if(ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE)) {
5007dd7cddfSDavid du Colombier 			upriv->ustats.rudpInErrors++;
5017dd7cddfSDavid du Colombier 			upriv->csumerr++;
5027dd7cddfSDavid du Colombier 			netlog(f, Logrudp, "rudp: checksum error %I\n", raddr);
5037dd7cddfSDavid du Colombier 			DPRINT("rudp: checksum error %I\n", raddr);
5047dd7cddfSDavid du Colombier 			freeblist(bp);
5057dd7cddfSDavid du Colombier 			return;
5067dd7cddfSDavid du Colombier 		}
5077dd7cddfSDavid du Colombier 	}
5087dd7cddfSDavid du Colombier 
5097dd7cddfSDavid du Colombier 	qlock(rudp);
5107dd7cddfSDavid du Colombier 
51180ee5cbfSDavid du Colombier 	c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
51280ee5cbfSDavid du Colombier 	if(c == nil){
513ac020a8fSDavid du Colombier 		/* no conversation found */
5147dd7cddfSDavid du Colombier 		upriv->ustats.rudpNoPorts++;
51580ee5cbfSDavid du Colombier 		qunlock(rudp);
51680ee5cbfSDavid du Colombier 		netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
5177dd7cddfSDavid du Colombier 			laddr, lport);
5187dd7cddfSDavid du Colombier 		uh->Unused = ottl;
5197dd7cddfSDavid du Colombier 		hnputs(uh->udpplen, olen);
5207dd7cddfSDavid du Colombier 		icmpnoconv(f, bp);
5217dd7cddfSDavid du Colombier 		freeblist(bp);
5227dd7cddfSDavid du Colombier 		return;
5237dd7cddfSDavid du Colombier 	}
5247dd7cddfSDavid du Colombier 	ucb = (Rudpcb*)c->ptcl;
5257dd7cddfSDavid du Colombier 	qlock(ucb);
5267dd7cddfSDavid du Colombier 	qunlock(rudp);
5277dd7cddfSDavid du Colombier 
5287dd7cddfSDavid du Colombier 	if(reliput(c, bp, raddr, rport) < 0){
5297dd7cddfSDavid du Colombier 		qunlock(ucb);
5307dd7cddfSDavid du Colombier 		freeb(bp);
5317dd7cddfSDavid du Colombier 		return;
5327dd7cddfSDavid du Colombier 	}
5337dd7cddfSDavid du Colombier 
5347dd7cddfSDavid du Colombier 	/*
5357dd7cddfSDavid du Colombier 	 * Trim the packet down to data size
5367dd7cddfSDavid du Colombier 	 */
5377dd7cddfSDavid du Colombier 
5387dd7cddfSDavid du Colombier 	len -= (UDP_RHDRSIZE-UDP_PHDRSIZE);
5397dd7cddfSDavid du Colombier 	bp = trimblock(bp, UDP_IPHDR+UDP_RHDRSIZE, len);
5407dd7cddfSDavid du Colombier 	if(bp == nil) {
5417dd7cddfSDavid du Colombier 		netlog(f, Logrudp, "rudp: len err %I.%d -> %I.%d\n",
5427dd7cddfSDavid du Colombier 			raddr, rport, laddr, lport);
5437dd7cddfSDavid du Colombier 		DPRINT("rudp: len err %I.%d -> %I.%d\n",
5447dd7cddfSDavid du Colombier 			raddr, rport, laddr, lport);
5457dd7cddfSDavid du Colombier 		upriv->lenerr++;
5467dd7cddfSDavid du Colombier 		return;
5477dd7cddfSDavid du Colombier 	}
5487dd7cddfSDavid du Colombier 
5497dd7cddfSDavid du Colombier 	netlog(f, Logrudpmsg, "rudp: %I.%d -> %I.%d l %d\n",
5507dd7cddfSDavid du Colombier 		raddr, rport, laddr, lport, len);
5517dd7cddfSDavid du Colombier 
5527dd7cddfSDavid du Colombier 	switch(ucb->headers){
553dc5a79c1SDavid du Colombier 	case 7:
554dc5a79c1SDavid du Colombier 		/* pass the src address */
555dc5a79c1SDavid du Colombier 		bp = padblock(bp, UDP_USEAD7);
556dc5a79c1SDavid du Colombier 		p = bp->rp;
557dc5a79c1SDavid du Colombier 		ipmove(p, raddr); p += IPaddrlen;
558dc5a79c1SDavid du Colombier 		ipmove(p, laddr); p += IPaddrlen;
559dc5a79c1SDavid du Colombier 		ipmove(p, ifc->lifc->local); p += IPaddrlen;
560dc5a79c1SDavid du Colombier 		hnputs(p, rport); p += 2;
561dc5a79c1SDavid du Colombier 		hnputs(p, lport);
562dc5a79c1SDavid du Colombier 		break;
5637dd7cddfSDavid du Colombier 	default:
5647dd7cddfSDavid du Colombier 		/* connection oriented rudp */
5657dd7cddfSDavid du Colombier 		if(ipcmp(c->raddr, IPnoaddr) == 0){
5667dd7cddfSDavid du Colombier 			/* save the src address in the conversation */
5677dd7cddfSDavid du Colombier 		 	ipmove(c->raddr, raddr);
5687dd7cddfSDavid du Colombier 			c->rport = rport;
5697dd7cddfSDavid du Colombier 
5707dd7cddfSDavid du Colombier 			/* reply with the same ip address (if not broadcast) */
5717dd7cddfSDavid du Colombier 			if(ipforme(f, laddr) == Runi)
5727dd7cddfSDavid du Colombier 				ipmove(c->laddr, laddr);
5737dd7cddfSDavid du Colombier 			else
5749a747e4fSDavid du Colombier 				v4tov6(c->laddr, ifc->lifc->local);
5757dd7cddfSDavid du Colombier 		}
5767dd7cddfSDavid du Colombier 		break;
5777dd7cddfSDavid du Colombier 	}
5787dd7cddfSDavid du Colombier 	if(bp->next)
5797dd7cddfSDavid du Colombier 		bp = concatblock(bp);
5807dd7cddfSDavid du Colombier 
5817dd7cddfSDavid du Colombier 	if(qfull(c->rq)) {
5827dd7cddfSDavid du Colombier 		netlog(f, Logrudp, "rudp: qfull %I.%d -> %I.%d\n", raddr, rport,
5837dd7cddfSDavid du Colombier 			laddr, lport);
5847dd7cddfSDavid du Colombier 		freeblist(bp);
5857dd7cddfSDavid du Colombier 	}
5867dd7cddfSDavid du Colombier 	else
5877dd7cddfSDavid du Colombier 		qpass(c->rq, bp);
5887dd7cddfSDavid du Colombier 
5897dd7cddfSDavid du Colombier 	qunlock(ucb);
5907dd7cddfSDavid du Colombier }
5917dd7cddfSDavid du Colombier 
5927dd7cddfSDavid du Colombier static char *rudpunknown = "unknown rudp ctl request";
5937dd7cddfSDavid du Colombier 
5947dd7cddfSDavid du Colombier char*
rudpctl(Conv * c,char ** f,int n)5957dd7cddfSDavid du Colombier rudpctl(Conv *c, char **f, int n)
5967dd7cddfSDavid du Colombier {
5977dd7cddfSDavid du Colombier 	Rudpcb *ucb;
5987dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
5997dd7cddfSDavid du Colombier 	int x;
6007dd7cddfSDavid du Colombier 
6017dd7cddfSDavid du Colombier 	ucb = (Rudpcb*)c->ptcl;
6027dd7cddfSDavid du Colombier 	if(n < 1)
6037dd7cddfSDavid du Colombier 		return rudpunknown;
6047dd7cddfSDavid du Colombier 
60584363d68SDavid du Colombier 	if(strcmp(f[0], "headers") == 0){
606f2c197d9SDavid du Colombier 		ucb->headers = 7;		/* new headers format */
6077dd7cddfSDavid du Colombier 		return nil;
6087dd7cddfSDavid du Colombier 	} else if(strcmp(f[0], "hangup") == 0){
6097dd7cddfSDavid du Colombier 		if(n < 3)
6107dd7cddfSDavid du Colombier 			return "bad syntax";
611ea58ad6fSDavid du Colombier 		if (parseip(ip, f[1]) == -1)
612ea58ad6fSDavid du Colombier 			return Ebadip;
6137dd7cddfSDavid du Colombier 		x = atoi(f[2]);
6147dd7cddfSDavid du Colombier 		qlock(ucb);
6157dd7cddfSDavid du Colombier 		relforget(c, ip, x, 1);
6167dd7cddfSDavid du Colombier 		qunlock(ucb);
6177dd7cddfSDavid du Colombier 		return nil;
6187dd7cddfSDavid du Colombier 	} else if(strcmp(f[0], "randdrop") == 0){
6197dd7cddfSDavid du Colombier 		x = 10;			/* default is 10% */
6207dd7cddfSDavid du Colombier 		if(n > 1)
6217dd7cddfSDavid du Colombier 			x = atoi(f[1]);
6227dd7cddfSDavid du Colombier 		if(x > 100 || x < 0)
6237dd7cddfSDavid du Colombier 			return "illegal rudp drop rate";
6247dd7cddfSDavid du Colombier 		ucb->randdrop = x;
6257dd7cddfSDavid du Colombier 		return nil;
6267dd7cddfSDavid du Colombier 	}
6277dd7cddfSDavid du Colombier 	return rudpunknown;
6287dd7cddfSDavid du Colombier }
6297dd7cddfSDavid du Colombier 
6307dd7cddfSDavid du Colombier void
rudpadvise(Proto * rudp,Block * bp,char * msg)6317dd7cddfSDavid du Colombier rudpadvise(Proto *rudp, Block *bp, char *msg)
6327dd7cddfSDavid du Colombier {
6337dd7cddfSDavid du Colombier 	Udphdr *h;
6347dd7cddfSDavid du Colombier 	uchar source[IPaddrlen], dest[IPaddrlen];
6357dd7cddfSDavid du Colombier 	ushort psource, pdest;
6367dd7cddfSDavid du Colombier 	Conv *s, **p;
6377dd7cddfSDavid du Colombier 
6387dd7cddfSDavid du Colombier 	h = (Udphdr*)(bp->rp);
6397dd7cddfSDavid du Colombier 
6407dd7cddfSDavid du Colombier 	v4tov6(dest, h->udpdst);
6417dd7cddfSDavid du Colombier 	v4tov6(source, h->udpsrc);
6427dd7cddfSDavid du Colombier 	psource = nhgets(h->udpsport);
6437dd7cddfSDavid du Colombier 	pdest = nhgets(h->udpdport);
6447dd7cddfSDavid du Colombier 
6457dd7cddfSDavid du Colombier 	/* Look for a connection */
6467dd7cddfSDavid du Colombier 	for(p = rudp->conv; *p; p++) {
6477dd7cddfSDavid du Colombier 		s = *p;
6487dd7cddfSDavid du Colombier 		if(s->rport == pdest)
6497dd7cddfSDavid du Colombier 		if(s->lport == psource)
6507dd7cddfSDavid du Colombier 		if(ipcmp(s->raddr, dest) == 0)
6517dd7cddfSDavid du Colombier 		if(ipcmp(s->laddr, source) == 0){
6527dd7cddfSDavid du Colombier 			qhangup(s->rq, msg);
6537dd7cddfSDavid du Colombier 			qhangup(s->wq, msg);
6547dd7cddfSDavid du Colombier 			break;
6557dd7cddfSDavid du Colombier 		}
6567dd7cddfSDavid du Colombier 	}
6577dd7cddfSDavid du Colombier 	freeblist(bp);
6587dd7cddfSDavid du Colombier }
6597dd7cddfSDavid du Colombier 
6607dd7cddfSDavid du Colombier int
rudpstats(Proto * rudp,char * buf,int len)6617dd7cddfSDavid du Colombier rudpstats(Proto *rudp, char *buf, int len)
6627dd7cddfSDavid du Colombier {
6637dd7cddfSDavid du Colombier 	Rudppriv *upriv;
6647dd7cddfSDavid du Colombier 
6657dd7cddfSDavid du Colombier 	upriv = rudp->priv;
6667dd7cddfSDavid du Colombier 	return snprint(buf, len, "%lud %lud %lud %lud %lud %lud\n",
6677dd7cddfSDavid du Colombier 		upriv->ustats.rudpInDatagrams,
6687dd7cddfSDavid du Colombier 		upriv->ustats.rudpNoPorts,
6697dd7cddfSDavid du Colombier 		upriv->ustats.rudpInErrors,
6707dd7cddfSDavid du Colombier 		upriv->ustats.rudpOutDatagrams,
6717dd7cddfSDavid du Colombier 		upriv->rxmits,
6727dd7cddfSDavid du Colombier 		upriv->orders);
6737dd7cddfSDavid du Colombier }
6747dd7cddfSDavid du Colombier 
6757dd7cddfSDavid du Colombier void
rudpinit(Fs * fs)6767dd7cddfSDavid du Colombier rudpinit(Fs *fs)
6777dd7cddfSDavid du Colombier {
6787dd7cddfSDavid du Colombier 
6797dd7cddfSDavid du Colombier 	Proto *rudp;
6807dd7cddfSDavid du Colombier 
6817dd7cddfSDavid du Colombier 	rudp = smalloc(sizeof(Proto));
6827dd7cddfSDavid du Colombier 	rudp->priv = smalloc(sizeof(Rudppriv));
6837dd7cddfSDavid du Colombier 	rudp->name = "rudp";
6847dd7cddfSDavid du Colombier 	rudp->connect = rudpconnect;
6857dd7cddfSDavid du Colombier 	rudp->announce = rudpannounce;
6867dd7cddfSDavid du Colombier 	rudp->ctl = rudpctl;
6877dd7cddfSDavid du Colombier 	rudp->state = rudpstate;
6887dd7cddfSDavid du Colombier 	rudp->create = rudpcreate;
6897dd7cddfSDavid du Colombier 	rudp->close = rudpclose;
6907dd7cddfSDavid du Colombier 	rudp->rcv = rudpiput;
6917dd7cddfSDavid du Colombier 	rudp->advise = rudpadvise;
6927dd7cddfSDavid du Colombier 	rudp->stats = rudpstats;
6937dd7cddfSDavid du Colombier 	rudp->ipproto = IP_UDPPROTO;
6947ec5746aSDavid du Colombier 	rudp->nc = 32;
6957dd7cddfSDavid du Colombier 	rudp->ptclsize = sizeof(Rudpcb);
6967dd7cddfSDavid du Colombier 
6977dd7cddfSDavid du Colombier 	Fsproto(fs, rudp);
6987dd7cddfSDavid du Colombier }
6997dd7cddfSDavid du Colombier 
7007dd7cddfSDavid du Colombier /*********************************************/
7017dd7cddfSDavid du Colombier /* Here starts the reliable helper functions */
7027dd7cddfSDavid du Colombier /*********************************************/
7037dd7cddfSDavid du Colombier /*
7047dd7cddfSDavid du Colombier  *  Enqueue a copy of an unacked block for possible retransmissions
7057dd7cddfSDavid du Colombier  */
7067dd7cddfSDavid du Colombier void
relackq(Reliable * r,Block * bp)7077dd7cddfSDavid du Colombier relackq(Reliable *r, Block *bp)
7087dd7cddfSDavid du Colombier {
7097dd7cddfSDavid du Colombier 	Block *np;
7107dd7cddfSDavid du Colombier 
7117dd7cddfSDavid du Colombier 	np = copyblock(bp, blocklen(bp));
7127dd7cddfSDavid du Colombier 	if(r->unacked)
7137dd7cddfSDavid du Colombier 		r->unackedtail->list = np;
7147dd7cddfSDavid du Colombier 	else {
7157dd7cddfSDavid du Colombier 		/* restart timer */
7167dd7cddfSDavid du Colombier 		r->timeout = 0;
7177dd7cddfSDavid du Colombier 		r->xmits = 1;
7187dd7cddfSDavid du Colombier 		r->unacked = np;
7197dd7cddfSDavid du Colombier 	}
7207dd7cddfSDavid du Colombier 	r->unackedtail = np;
7217dd7cddfSDavid du Colombier 	np->list = nil;
7227dd7cddfSDavid du Colombier }
7237dd7cddfSDavid du Colombier 
7247dd7cddfSDavid du Colombier /*
7257dd7cddfSDavid du Colombier  *  retransmit unacked blocks
7267dd7cddfSDavid du Colombier  */
7277dd7cddfSDavid du Colombier void
relackproc(void * a)7287dd7cddfSDavid du Colombier relackproc(void *a)
7297dd7cddfSDavid du Colombier {
7307dd7cddfSDavid du Colombier 	Rudpcb *ucb;
7317dd7cddfSDavid du Colombier 	Proto *rudp;
7327dd7cddfSDavid du Colombier 	Reliable *r;
7337dd7cddfSDavid du Colombier 	Conv **s, *c;
7347dd7cddfSDavid du Colombier 
7357dd7cddfSDavid du Colombier 	rudp = (Proto *)a;
7367dd7cddfSDavid du Colombier 
7377dd7cddfSDavid du Colombier loop:
738dc5a79c1SDavid du Colombier 	tsleep(&up->sleep, return0, 0, Rudptickms);
7397dd7cddfSDavid du Colombier 
7407dd7cddfSDavid du Colombier 	for(s = rudp->conv; *s; s++) {
7417dd7cddfSDavid du Colombier 		c = *s;
7427dd7cddfSDavid du Colombier 		ucb = (Rudpcb*)c->ptcl;
7437dd7cddfSDavid du Colombier 		qlock(ucb);
7447dd7cddfSDavid du Colombier 
7457dd7cddfSDavid du Colombier 		for(r = ucb->r; r; r = r->next) {
7467dd7cddfSDavid du Colombier 			if(r->unacked != nil){
7477dd7cddfSDavid du Colombier 				r->timeout += Rudptickms;
7487dd7cddfSDavid du Colombier 				if(r->timeout > Rudprxms*r->xmits)
7497dd7cddfSDavid du Colombier 					relrexmit(c, r);
7507dd7cddfSDavid du Colombier 			}
7517dd7cddfSDavid du Colombier 			if(r->acksent != r->rcvseq)
7527dd7cddfSDavid du Colombier 				relsendack(c, r, 0);
7537dd7cddfSDavid du Colombier 		}
7547dd7cddfSDavid du Colombier 		qunlock(ucb);
7557dd7cddfSDavid du Colombier 	}
7567dd7cddfSDavid du Colombier 	goto loop;
7577dd7cddfSDavid du Colombier }
7587dd7cddfSDavid du Colombier 
7597dd7cddfSDavid du Colombier /*
7607dd7cddfSDavid du Colombier  *  get the state record for a conversation
7617dd7cddfSDavid du Colombier  */
7627dd7cddfSDavid du Colombier Reliable*
relstate(Rudpcb * ucb,uchar * addr,ushort port,char * from)7637dd7cddfSDavid du Colombier relstate(Rudpcb *ucb, uchar *addr, ushort port, char *from)
7647dd7cddfSDavid du Colombier {
7657dd7cddfSDavid du Colombier 	Reliable *r, **l;
7667dd7cddfSDavid du Colombier 
7677dd7cddfSDavid du Colombier 	l = &ucb->r;
7687dd7cddfSDavid du Colombier 	for(r = *l; r; r = *l){
7697dd7cddfSDavid du Colombier 		if(memcmp(addr, r->addr, IPaddrlen) == 0 &&
7707dd7cddfSDavid du Colombier 		    port == r->port)
7717dd7cddfSDavid du Colombier 			break;
7727dd7cddfSDavid du Colombier 		l = &r->next;
7737dd7cddfSDavid du Colombier 	}
7747dd7cddfSDavid du Colombier 
7757dd7cddfSDavid du Colombier 	/* no state for this addr/port, create some */
7767dd7cddfSDavid du Colombier 	if(r == nil){
7777dd7cddfSDavid du Colombier 		while(generation == 0)
7787dd7cddfSDavid du Colombier 			generation = rand();
7797dd7cddfSDavid du Colombier 
7807dd7cddfSDavid du Colombier 		DPRINT("from %s new state %lud for %I!%ud\n",
7817dd7cddfSDavid du Colombier 		        from, generation, addr, port);
7827dd7cddfSDavid du Colombier 
7837dd7cddfSDavid du Colombier 		r = smalloc(sizeof(Reliable));
7847dd7cddfSDavid du Colombier 		memmove(r->addr, addr, IPaddrlen);
7857dd7cddfSDavid du Colombier 		r->port = port;
7867dd7cddfSDavid du Colombier 		r->unacked = 0;
7877dd7cddfSDavid du Colombier 		if(generation == Hangupgen)
7887dd7cddfSDavid du Colombier 			generation++;
7897dd7cddfSDavid du Colombier 		r->sndgen = generation++;
7907dd7cddfSDavid du Colombier 		r->sndseq = 0;
7917dd7cddfSDavid du Colombier 		r->ackrcvd = 0;
7927dd7cddfSDavid du Colombier 		r->rcvgen = 0;
7937dd7cddfSDavid du Colombier 		r->rcvseq = 0;
7947dd7cddfSDavid du Colombier 		r->acksent = 0;
7957dd7cddfSDavid du Colombier 		r->xmits = 0;
7967dd7cddfSDavid du Colombier 		r->timeout = 0;
7977dd7cddfSDavid du Colombier 		r->ref = 0;
7987dd7cddfSDavid du Colombier 		incref(r);	/* one reference for being in the list */
7997dd7cddfSDavid du Colombier 
8007dd7cddfSDavid du Colombier 		*l = r;
8017dd7cddfSDavid du Colombier 	}
8027dd7cddfSDavid du Colombier 
8037dd7cddfSDavid du Colombier 	incref(r);
8047dd7cddfSDavid du Colombier 	return r;
8057dd7cddfSDavid du Colombier }
8067dd7cddfSDavid du Colombier 
8077dd7cddfSDavid du Colombier void
relput(Reliable * r)8087dd7cddfSDavid du Colombier relput(Reliable *r)
8097dd7cddfSDavid du Colombier {
8107dd7cddfSDavid du Colombier 	if(decref(r) == 0)
8117dd7cddfSDavid du Colombier 		free(r);
8127dd7cddfSDavid du Colombier }
8137dd7cddfSDavid du Colombier 
8147dd7cddfSDavid du Colombier /*
8157dd7cddfSDavid du Colombier  *  forget a Reliable state
8167dd7cddfSDavid du Colombier  */
8177dd7cddfSDavid du Colombier void
relforget(Conv * c,uchar * ip,int port,int originator)8187dd7cddfSDavid du Colombier relforget(Conv *c, uchar *ip, int port, int originator)
8197dd7cddfSDavid du Colombier {
8207dd7cddfSDavid du Colombier 	Rudpcb *ucb;
8217dd7cddfSDavid du Colombier 	Reliable *r, **l;
8227dd7cddfSDavid du Colombier 
8237dd7cddfSDavid du Colombier 	ucb = (Rudpcb*)c->ptcl;
8247dd7cddfSDavid du Colombier 
8257dd7cddfSDavid du Colombier 	l = &ucb->r;
8267dd7cddfSDavid du Colombier 	for(r = *l; r; r = *l){
8277dd7cddfSDavid du Colombier 		if(ipcmp(ip, r->addr) == 0 && port == r->port){
8287dd7cddfSDavid du Colombier 			*l = r->next;
8297dd7cddfSDavid du Colombier 			if(originator)
8307dd7cddfSDavid du Colombier 				relsendack(c, r, 1);
8317dd7cddfSDavid du Colombier 			relhangup(c, r);
8327dd7cddfSDavid du Colombier 			relput(r);	/* remove from the list */
8337dd7cddfSDavid du Colombier 			break;
8347dd7cddfSDavid du Colombier 		}
8357dd7cddfSDavid du Colombier 		l = &r->next;
8367dd7cddfSDavid du Colombier 	}
8377dd7cddfSDavid du Colombier }
8387dd7cddfSDavid du Colombier 
8397dd7cddfSDavid du Colombier /*
8407dd7cddfSDavid du Colombier  *  process a rcvd reliable packet. return -1 if not to be passed to user process,
8417dd7cddfSDavid du Colombier  *  0 therwise.
8427dd7cddfSDavid du Colombier  *
8437dd7cddfSDavid du Colombier  *  called with ucb locked.
8447dd7cddfSDavid du Colombier  */
8457dd7cddfSDavid du Colombier int
reliput(Conv * c,Block * bp,uchar * addr,ushort port)8467dd7cddfSDavid du Colombier reliput(Conv *c, Block *bp, uchar *addr, ushort port)
8477dd7cddfSDavid du Colombier {
8487dd7cddfSDavid du Colombier 	Block *nbp;
8497dd7cddfSDavid du Colombier 	Rudpcb *ucb;
8507dd7cddfSDavid du Colombier 	Rudppriv *upriv;
8517dd7cddfSDavid du Colombier 	Udphdr *uh;
8527dd7cddfSDavid du Colombier 	Reliable *r;
8537dd7cddfSDavid du Colombier 	Rudphdr *rh;
8547dd7cddfSDavid du Colombier 	ulong seq, ack, sgen, agen, ackreal;
8557dd7cddfSDavid du Colombier 	int rv = -1;
8567dd7cddfSDavid du Colombier 
8577dd7cddfSDavid du Colombier 	/* get fields */
8587dd7cddfSDavid du Colombier 	uh = (Udphdr*)(bp->rp);
8597dd7cddfSDavid du Colombier 	rh = (Rudphdr*)uh;
8607dd7cddfSDavid du Colombier 	seq = nhgetl(rh->relseq);
8617dd7cddfSDavid du Colombier 	sgen = nhgetl(rh->relsgen);
8627dd7cddfSDavid du Colombier 	ack = nhgetl(rh->relack);
8637dd7cddfSDavid du Colombier 	agen = nhgetl(rh->relagen);
8647dd7cddfSDavid du Colombier 
8657dd7cddfSDavid du Colombier 	upriv = c->p->priv;
8667dd7cddfSDavid du Colombier 	ucb = (Rudpcb*)c->ptcl;
8677dd7cddfSDavid du Colombier 	r = relstate(ucb, addr, port, "input");
8687dd7cddfSDavid du Colombier 
8697dd7cddfSDavid du Colombier 	DPRINT("rcvd %lud/%lud, %lud/%lud, r->sndgen = %lud\n",
8707dd7cddfSDavid du Colombier 		seq, sgen, ack, agen, r->sndgen);
8717dd7cddfSDavid du Colombier 
8727dd7cddfSDavid du Colombier 	/* if acking an incorrect generation, ignore */
8737dd7cddfSDavid du Colombier 	if(ack && agen != r->sndgen)
8747dd7cddfSDavid du Colombier 		goto out;
8757dd7cddfSDavid du Colombier 
8767dd7cddfSDavid du Colombier 	/* Look for a hangup */
8777dd7cddfSDavid du Colombier 	if(sgen == Hangupgen) {
8787dd7cddfSDavid du Colombier 		if(agen == r->sndgen)
8797dd7cddfSDavid du Colombier 			relforget(c, addr, port, 0);
8807dd7cddfSDavid du Colombier 		goto out;
8817dd7cddfSDavid du Colombier 	}
8827dd7cddfSDavid du Colombier 
8837dd7cddfSDavid du Colombier 	/* make sure we're not talking to a new remote side */
8847dd7cddfSDavid du Colombier 	if(r->rcvgen != sgen){
8857dd7cddfSDavid du Colombier 		if(seq != 0 && seq != 1)
8867dd7cddfSDavid du Colombier 			goto out;
8877dd7cddfSDavid du Colombier 
8887dd7cddfSDavid du Colombier 		/* new connection */
8897dd7cddfSDavid du Colombier 		if(r->rcvgen != 0){
8907dd7cddfSDavid du Colombier 			DPRINT("new con r->rcvgen = %lud, sgen = %lud\n", r->rcvgen, sgen);
8917dd7cddfSDavid du Colombier 			relhangup(c, r);
8927dd7cddfSDavid du Colombier 		}
8937dd7cddfSDavid du Colombier 		r->rcvgen = sgen;
8947dd7cddfSDavid du Colombier 	}
8957dd7cddfSDavid du Colombier 
8967dd7cddfSDavid du Colombier 	/* dequeue acked packets */
8977dd7cddfSDavid du Colombier 	if(ack && agen == r->sndgen){
8987dd7cddfSDavid du Colombier 		ackreal = 0;
8997dd7cddfSDavid du Colombier 		while(r->unacked != nil && INSEQ(ack, r->ackrcvd, r->sndseq)){
9007dd7cddfSDavid du Colombier 			nbp = r->unacked;
9017dd7cddfSDavid du Colombier 			r->unacked = nbp->list;
9027dd7cddfSDavid du Colombier 			DPRINT("%lud/%lud acked, r->sndgen = %lud\n",
9037dd7cddfSDavid du Colombier 			       ack, agen, r->sndgen);
9047dd7cddfSDavid du Colombier 			freeb(nbp);
9057dd7cddfSDavid du Colombier 			r->ackrcvd = NEXTSEQ(r->ackrcvd);
9067dd7cddfSDavid du Colombier 			ackreal = 1;
9077dd7cddfSDavid du Colombier 		}
9087dd7cddfSDavid du Colombier 
9097dd7cddfSDavid du Colombier 		/* flow control */
9107dd7cddfSDavid du Colombier 		if(UNACKED(r) < Maxunacked/8 && r->blocked)
9117dd7cddfSDavid du Colombier 			wakeup(&r->vous);
9127dd7cddfSDavid du Colombier 
9137dd7cddfSDavid du Colombier 		/*
9147dd7cddfSDavid du Colombier 		 *  retransmit next packet if the acked packet
9157dd7cddfSDavid du Colombier 		 *  was transmitted more than once
9167dd7cddfSDavid du Colombier 		 */
9177dd7cddfSDavid du Colombier 		if(ackreal && r->unacked != nil){
9187dd7cddfSDavid du Colombier 			r->timeout = 0;
9197dd7cddfSDavid du Colombier 			if(r->xmits > 1){
9207dd7cddfSDavid du Colombier 				r->xmits = 1;
9217dd7cddfSDavid du Colombier 				relrexmit(c, r);
9227dd7cddfSDavid du Colombier 			}
9237dd7cddfSDavid du Colombier 		}
9247dd7cddfSDavid du Colombier 
9257dd7cddfSDavid du Colombier 	}
9267dd7cddfSDavid du Colombier 
9277dd7cddfSDavid du Colombier 	/* no message or input queue full */
9287dd7cddfSDavid du Colombier 	if(seq == 0 || qfull(c->rq))
9297dd7cddfSDavid du Colombier 		goto out;
9307dd7cddfSDavid du Colombier 
9317dd7cddfSDavid du Colombier 	/* refuse out of order delivery */
9327dd7cddfSDavid du Colombier 	if(seq != NEXTSEQ(r->rcvseq)){
9337dd7cddfSDavid du Colombier 		relsendack(c, r, 0);	/* tell him we got it already */
9347dd7cddfSDavid du Colombier 		upriv->orders++;
9357dd7cddfSDavid du Colombier 		DPRINT("out of sequence %lud not %lud\n", seq, NEXTSEQ(r->rcvseq));
9367dd7cddfSDavid du Colombier 		goto out;
9377dd7cddfSDavid du Colombier 	}
9387dd7cddfSDavid du Colombier 	r->rcvseq = seq;
9397dd7cddfSDavid du Colombier 
9407dd7cddfSDavid du Colombier 	rv = 0;
9417dd7cddfSDavid du Colombier out:
9427dd7cddfSDavid du Colombier 	relput(r);
9437dd7cddfSDavid du Colombier 	return rv;
9447dd7cddfSDavid du Colombier }
9457dd7cddfSDavid du Colombier 
9467dd7cddfSDavid du Colombier void
relsendack(Conv * c,Reliable * r,int hangup)9477dd7cddfSDavid du Colombier relsendack(Conv *c, Reliable *r, int hangup)
9487dd7cddfSDavid du Colombier {
9497dd7cddfSDavid du Colombier 	Udphdr *uh;
9507dd7cddfSDavid du Colombier 	Block *bp;
9517dd7cddfSDavid du Colombier 	Rudphdr *rh;
9527dd7cddfSDavid du Colombier 	int ptcllen;
9537dd7cddfSDavid du Colombier 	Fs *f;
9547dd7cddfSDavid du Colombier 
9557dd7cddfSDavid du Colombier 	bp = allocb(UDP_IPHDR + UDP_RHDRSIZE);
9567dd7cddfSDavid du Colombier 	if(bp == nil)
9577dd7cddfSDavid du Colombier 		return;
9587dd7cddfSDavid du Colombier 	bp->wp += UDP_IPHDR + UDP_RHDRSIZE;
9597dd7cddfSDavid du Colombier 	f = c->p->f;
9607dd7cddfSDavid du Colombier 	uh = (Udphdr *)(bp->rp);
9613ff48bf5SDavid du Colombier 	uh->vihl = IP_VER4;
9627dd7cddfSDavid du Colombier 	rh = (Rudphdr*)uh;
9637dd7cddfSDavid du Colombier 
9647dd7cddfSDavid du Colombier 	ptcllen = (UDP_RHDRSIZE-UDP_PHDRSIZE);
9657dd7cddfSDavid du Colombier 	uh->Unused = 0;
9667dd7cddfSDavid du Colombier 	uh->udpproto = IP_UDPPROTO;
9677dd7cddfSDavid du Colombier 	uh->frag[0] = 0;
9687dd7cddfSDavid du Colombier 	uh->frag[1] = 0;
9697dd7cddfSDavid du Colombier 	hnputs(uh->udpplen, ptcllen);
9707dd7cddfSDavid du Colombier 
9717dd7cddfSDavid du Colombier 	v6tov4(uh->udpdst, r->addr);
9727dd7cddfSDavid du Colombier 	hnputs(uh->udpdport, r->port);
9737dd7cddfSDavid du Colombier 	hnputs(uh->udpsport, c->lport);
9747dd7cddfSDavid du Colombier 	if(ipcmp(c->laddr, IPnoaddr) == 0)
9757dd7cddfSDavid du Colombier 		findlocalip(f, c->laddr, c->raddr);
9767dd7cddfSDavid du Colombier 	v6tov4(uh->udpsrc, c->laddr);
9777dd7cddfSDavid du Colombier 	hnputs(uh->udplen, ptcllen);
9787dd7cddfSDavid du Colombier 
9797dd7cddfSDavid du Colombier 	if(hangup)
9807dd7cddfSDavid du Colombier 		hnputl(rh->relsgen, Hangupgen);
9817dd7cddfSDavid du Colombier 	else
9827dd7cddfSDavid du Colombier 		hnputl(rh->relsgen, r->sndgen);
9837dd7cddfSDavid du Colombier 	hnputl(rh->relseq, 0);
9847dd7cddfSDavid du Colombier 	hnputl(rh->relagen, r->rcvgen);
9857dd7cddfSDavid du Colombier 	hnputl(rh->relack, r->rcvseq);
9867dd7cddfSDavid du Colombier 
9877dd7cddfSDavid du Colombier 	if(r->acksent < r->rcvseq)
9887dd7cddfSDavid du Colombier 		r->acksent = r->rcvseq;
9897dd7cddfSDavid du Colombier 
9907dd7cddfSDavid du Colombier 	uh->udpcksum[0] = 0;
9917dd7cddfSDavid du Colombier 	uh->udpcksum[1] = 0;
9927dd7cddfSDavid du Colombier 	hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, UDP_RHDRSIZE));
9937dd7cddfSDavid du Colombier 
9947dd7cddfSDavid du Colombier 	DPRINT("sendack: %lud/%lud, %lud/%lud\n", 0L, r->sndgen, r->rcvseq, r->rcvgen);
9957dd7cddfSDavid du Colombier 	doipoput(c, f, bp, 0, c->ttl, c->tos);
9967dd7cddfSDavid du Colombier }
9977dd7cddfSDavid du Colombier 
9987dd7cddfSDavid du Colombier 
9997dd7cddfSDavid du Colombier /*
10007dd7cddfSDavid du Colombier  *  called with ucb locked (and c locked if user initiated close)
10017dd7cddfSDavid du Colombier  */
10027dd7cddfSDavid du Colombier void
relhangup(Conv * c,Reliable * r)10037dd7cddfSDavid du Colombier relhangup(Conv *c, Reliable *r)
10047dd7cddfSDavid du Colombier {
10057dd7cddfSDavid du Colombier 	int n;
10067dd7cddfSDavid du Colombier 	Block *bp;
10079a747e4fSDavid du Colombier 	char hup[ERRMAX];
10087dd7cddfSDavid du Colombier 
10097dd7cddfSDavid du Colombier 	n = snprint(hup, sizeof(hup), "hangup %I!%d", r->addr, r->port);
10107dd7cddfSDavid du Colombier 	qproduce(c->eq, hup, n);
10117dd7cddfSDavid du Colombier 
10127dd7cddfSDavid du Colombier 	/*
10137dd7cddfSDavid du Colombier 	 *  dump any unacked outgoing messages
10147dd7cddfSDavid du Colombier 	 */
10157dd7cddfSDavid du Colombier 	for(bp = r->unacked; bp != nil; bp = r->unacked){
10167dd7cddfSDavid du Colombier 		r->unacked = bp->list;
10177dd7cddfSDavid du Colombier 		bp->list = nil;
10187dd7cddfSDavid du Colombier 		freeb(bp);
10197dd7cddfSDavid du Colombier 	}
10207dd7cddfSDavid du Colombier 
10217dd7cddfSDavid du Colombier 	r->rcvgen = 0;
10227dd7cddfSDavid du Colombier 	r->rcvseq = 0;
10237dd7cddfSDavid du Colombier 	r->acksent = 0;
10247dd7cddfSDavid du Colombier 	if(generation == Hangupgen)
10257dd7cddfSDavid du Colombier 		generation++;
10267dd7cddfSDavid du Colombier 	r->sndgen = generation++;
10277dd7cddfSDavid du Colombier 	r->sndseq = 0;
10287dd7cddfSDavid du Colombier 	r->ackrcvd = 0;
10297dd7cddfSDavid du Colombier 	r->xmits = 0;
10307dd7cddfSDavid du Colombier 	r->timeout = 0;
10317dd7cddfSDavid du Colombier 	wakeup(&r->vous);
10327dd7cddfSDavid du Colombier }
10337dd7cddfSDavid du Colombier 
10347dd7cddfSDavid du Colombier /*
10357dd7cddfSDavid du Colombier  *  called with ucb locked
10367dd7cddfSDavid du Colombier  */
10377dd7cddfSDavid du Colombier void
relrexmit(Conv * c,Reliable * r)10387dd7cddfSDavid du Colombier relrexmit(Conv *c, Reliable *r)
10397dd7cddfSDavid du Colombier {
10407dd7cddfSDavid du Colombier 	Rudppriv *upriv;
10417dd7cddfSDavid du Colombier 	Block *np;
10427dd7cddfSDavid du Colombier 	Fs *f;
10437dd7cddfSDavid du Colombier 
10447dd7cddfSDavid du Colombier 	upriv = c->p->priv;
10457dd7cddfSDavid du Colombier 	f = c->p->f;
10467dd7cddfSDavid du Colombier 	r->timeout = 0;
10477dd7cddfSDavid du Colombier 	if(r->xmits++ > Rudpmaxxmit){
10487dd7cddfSDavid du Colombier 		relhangup(c, r);
10497dd7cddfSDavid du Colombier 		return;
10507dd7cddfSDavid du Colombier 	}
10517dd7cddfSDavid du Colombier 
10527dd7cddfSDavid du Colombier 	upriv->rxmits++;
10537dd7cddfSDavid du Colombier 	np = copyblock(r->unacked, blocklen(r->unacked));
10547dd7cddfSDavid du Colombier 	DPRINT("rxmit r->ackrvcd+1 = %lud\n", r->ackrcvd+1);
10557dd7cddfSDavid du Colombier 	doipoput(c, f, np, 0, c->ttl, c->tos);
10567dd7cddfSDavid du Colombier }
1057