Add retry mechanisms for Econet, so that if a four-way handshake doesn't
complete for some reason, we defer it for a bit and then try again. This gets ping down to 0% packet loss. Of course, ping _should_ have been at 0% packet loss anyway, and that's the next thing to deal with.
This commit is contained in:
parent
aece5a2ae7
commit
5ddc1e1310
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: if_eca.c,v 1.3 2001/09/16 15:08:40 bjh21 Exp $ */
|
||||
/* $NetBSD: if_eca.c,v 1.4 2001/09/17 22:41:59 bjh21 Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 Ben Harris
|
||||
@ -29,7 +29,7 @@
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
__KERNEL_RCSID(0, "$NetBSD: if_eca.c,v 1.3 2001/09/16 15:08:40 bjh21 Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: if_eca.c,v 1.4 2001/09/17 22:41:59 bjh21 Exp $");
|
||||
|
||||
#include <sys/device.h>
|
||||
#include <sys/malloc.h>
|
||||
@ -376,6 +376,8 @@ eca_stop(struct ifnet *ifp, int disable)
|
||||
|
||||
ifp->if_flags &= ~IFF_RUNNING;
|
||||
|
||||
eco_stop(ifp, disable);
|
||||
|
||||
/* Interrupts disabled, no DMA, hold Tx and Rx in reset. */
|
||||
sc->sc_cr1 = MC6854_CR1_RX_RS | MC6854_CR1_TX_RS;
|
||||
bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: if_eco.h,v 1.3 2001/09/16 15:08:39 bjh21 Exp $ */
|
||||
/* $NetBSD: if_eco.h,v 1.4 2001/09/17 22:42:00 bjh21 Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 Ben Harris
|
||||
@ -30,7 +30,9 @@
|
||||
#ifndef _NET_IF_ECO_H_
|
||||
#define _NET_IF_ECO_H_
|
||||
|
||||
#include <sys/callout.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
@ -108,15 +110,29 @@ struct eco_arp {
|
||||
u_int8_t ecar_tpa[4];
|
||||
};
|
||||
|
||||
/*
|
||||
* Common structure used to store state about an Econet interface.
|
||||
*/
|
||||
enum eco_state {
|
||||
ECO_UNKNOWN, ECO_IDLE, ECO_SCOUT_RCVD,
|
||||
ECO_SCOUT_SENT, ECO_DATA_SENT, ECO_IMMED_SENT,
|
||||
ECO_DONE
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This structure contains a packet that might need retransmitting,
|
||||
* together with a callout to trigger retransmission. They're kept on
|
||||
* a per-interface list so they can be freed when an interface is
|
||||
* downed.
|
||||
*/
|
||||
struct eco_retry {
|
||||
LIST_ENTRY(eco_retry) er_link;
|
||||
struct callout er_callout;
|
||||
struct mbuf *er_packet;
|
||||
struct ifnet *er_ifp;
|
||||
};
|
||||
|
||||
/*
|
||||
* Common structure used to store state about an Econet interface.
|
||||
*/
|
||||
struct ecocom {
|
||||
struct ifnet ec_if;
|
||||
int (*ec_claimwire)(struct ifnet *);
|
||||
@ -124,12 +140,14 @@ struct ecocom {
|
||||
enum eco_state ec_state;
|
||||
struct mbuf *ec_scout;
|
||||
struct mbuf *ec_packet;
|
||||
LIST_HEAD(, eco_retry) ec_retries;
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
void eco_ifattach(struct ifnet *, const u_int8_t *);
|
||||
void eco_ifdetach(struct ifnet *);
|
||||
int eco_init(struct ifnet *);
|
||||
void eco_stop(struct ifnet *, int);
|
||||
|
||||
char *eco_sprintf(const u_int8_t *);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: if_ecosubr.c,v 1.7 2001/09/16 15:08:39 bjh21 Exp $ */
|
||||
/* $NetBSD: if_ecosubr.c,v 1.8 2001/09/17 22:42:00 bjh21 Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 Ben Harris
|
||||
@ -66,7 +66,7 @@
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
__KERNEL_RCSID(0, "$NetBSD: if_ecosubr.c,v 1.7 2001/09/16 15:08:39 bjh21 Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: if_ecosubr.c,v 1.8 2001/09/17 22:42:00 bjh21 Exp $");
|
||||
|
||||
#include <sys/errno.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -93,6 +93,13 @@ __KERNEL_RCSID(0, "$NetBSD: if_ecosubr.c,v 1.7 2001/09/16 15:08:39 bjh21 Exp $")
|
||||
#include <netinet/in_var.h>
|
||||
#endif
|
||||
|
||||
#define ECO_MAUX_RETRYPARMS 0
|
||||
|
||||
struct eco_retryparms {
|
||||
int erp_delay;
|
||||
int erp_count;
|
||||
};
|
||||
|
||||
/* Default broadcast address */
|
||||
static const u_int8_t eco_broadcastaddr[] = { 0xff, 0xff };
|
||||
|
||||
@ -106,10 +113,14 @@ static int eco_interestingp(struct ifnet *ifp, struct mbuf *m);
|
||||
static struct mbuf *eco_immediate(struct ifnet *ifp, struct mbuf *m);
|
||||
static struct mbuf *eco_ack(struct ifnet *ifp, struct mbuf *m);
|
||||
|
||||
static void eco_defer(struct ifnet *, struct mbuf *, int);
|
||||
static void eco_retry_free(struct eco_retry *er);
|
||||
static void eco_retry(void *);
|
||||
|
||||
void
|
||||
eco_ifattach(struct ifnet *ifp, const u_int8_t *lla)
|
||||
{
|
||||
/* struct ecocom *ec = (void *)ifp; */
|
||||
struct ecocom *ec = (void *)ifp;
|
||||
|
||||
ifp->if_type = IFT_OTHER;
|
||||
ifp->if_addrlen = ECO_ADDR_LEN;
|
||||
@ -128,6 +139,9 @@ eco_ifattach(struct ifnet *ifp, const u_int8_t *lla)
|
||||
|
||||
/* XXX cast safe? */
|
||||
ifp->if_broadcastaddr = (u_int8_t *)eco_broadcastaddr;
|
||||
|
||||
LIST_INIT(&ec->ec_retries);
|
||||
|
||||
#if NBPFILTER > 0
|
||||
bpfattach(ifp, ifp->if_dlt, ECO_HDR_LEN);
|
||||
#endif
|
||||
@ -142,10 +156,20 @@ int
|
||||
eco_init(struct ifnet *ifp) {
|
||||
struct ecocom *ec = (struct ecocom *)ifp;
|
||||
|
||||
ec->ec_state = ECO_UNKNOWN;
|
||||
if ((ifp->if_flags & IFF_RUNNING) == 0)
|
||||
ec->ec_state = ECO_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
eco_stop(struct ifnet *ifp, int disable)
|
||||
{
|
||||
struct ecocom *ec = (struct ecocom *)ifp;
|
||||
|
||||
while (!LIST_EMPTY(&ec->ec_retries))
|
||||
eco_retry_free(LIST_FIRST(&ec->ec_retries));
|
||||
}
|
||||
|
||||
static int
|
||||
eco_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
|
||||
struct rtentry *rt0)
|
||||
@ -156,6 +180,9 @@ eco_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
|
||||
struct rtentry *rt;
|
||||
int hdrcmplt;
|
||||
size_t len;
|
||||
int delay, count;
|
||||
struct mbuf *maux;
|
||||
struct eco_retryparms *erp;
|
||||
#ifdef INET
|
||||
struct mbuf *m1;
|
||||
struct arphdr *ah;
|
||||
@ -204,6 +231,8 @@ eco_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
|
||||
IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
|
||||
|
||||
hdrcmplt = 0;
|
||||
delay = hz / 16;
|
||||
count = 16;
|
||||
switch (dst->sa_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
@ -287,6 +316,17 @@ eco_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
|
||||
memcpy(eh->eco_shost, LLADDR(ifp->if_sadl),
|
||||
ECO_ADDR_LEN);
|
||||
|
||||
if ((m->m_flags & M_BCAST) == 0) {
|
||||
/* Attach retry info to packet. */
|
||||
maux = m_aux_add(m, AF_LINK, ECO_MAUX_RETRYPARMS);
|
||||
if (maux == NULL)
|
||||
senderr(ENOBUFS);
|
||||
erp = mtod(maux, struct eco_retryparms *);
|
||||
erp->erp_delay = delay;
|
||||
erp->erp_count = count;
|
||||
maux->m_len = sizeof(struct eco_retryparms);
|
||||
}
|
||||
|
||||
#ifdef PFIL_HOOKS
|
||||
if ((error = pfil_run_hooks(&ifp->if_pfil, &m, ifp, PFIL_OUT)) != 0)
|
||||
return (error);
|
||||
@ -453,6 +493,7 @@ eco_input(struct ifnet *ifp, struct mbuf *m)
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
|
||||
s = splnet();
|
||||
if (IF_QFULL(inq)) {
|
||||
IF_DROP(inq);
|
||||
@ -483,8 +524,12 @@ eco_start(struct ifnet *ifp)
|
||||
} else {
|
||||
ec->ec_packet = m;
|
||||
m = m_copym(m, 0, ECO_HDR_LEN, M_DONTWAIT);
|
||||
/* m_copym moves the aux ptr. Move it back. */
|
||||
ec->ec_packet->m_pkthdr.aux = m->m_pkthdr.aux;
|
||||
m->m_pkthdr.aux = NULL;
|
||||
if (m == NULL) {
|
||||
m_freem(ec->ec_packet);
|
||||
ec->ec_packet = NULL;
|
||||
return;
|
||||
}
|
||||
ec->ec_txframe(ifp, m);
|
||||
@ -648,14 +693,19 @@ eco_inputframe(struct ifnet *ifp, struct mbuf *m)
|
||||
m_freem(m);
|
||||
/* Chop out the control and port bytes. */
|
||||
m0 = m_copym(ec->ec_packet, 0, ECO_SHDR_LEN, M_DONTWAIT);
|
||||
/* Put the aux ptr back where it belongs. */
|
||||
ec->ec_packet->m_pkthdr.aux = m0->m_pkthdr.aux;
|
||||
m0->m_pkthdr.aux = NULL;
|
||||
if (m0 == NULL) {
|
||||
m_freem(ec->ec_packet);
|
||||
return NULL;
|
||||
}
|
||||
m = m_copypacket(ec->ec_packet, M_DONTWAIT);
|
||||
if (m == NULL) {
|
||||
/* m_copypacket moves the aux ptr, hence this little dance. */
|
||||
m = ec->ec_packet;
|
||||
ec->ec_packet = m_copypacket(m, M_DONTWAIT);
|
||||
if (ec->ec_packet == NULL) {
|
||||
m_freem(m0);
|
||||
m_freem(ec->ec_packet);
|
||||
m_freem(m);
|
||||
return NULL;
|
||||
}
|
||||
m_adj(m, ECO_HDR_LEN);
|
||||
@ -748,10 +798,37 @@ void
|
||||
eco_inputidle(struct ifnet *ifp)
|
||||
{
|
||||
struct ecocom *ec = (void *)ifp;
|
||||
struct mbuf *m, *maux;
|
||||
struct eco_retryparms *erp;
|
||||
|
||||
switch (ec->ec_state) {
|
||||
case ECO_SCOUT_SENT:
|
||||
case ECO_DATA_SENT:
|
||||
case ECO_IMMED_SENT:
|
||||
/* Outgoing packet failed. Check if we should retry. */
|
||||
m = ec->ec_packet;
|
||||
ec->ec_packet = NULL;
|
||||
maux = m_aux_find(m, AF_LINK, ECO_MAUX_RETRYPARMS);
|
||||
if (maux == NULL)
|
||||
m_freem(m);
|
||||
else {
|
||||
erp = mtod(maux, struct eco_retryparms *);
|
||||
if (--erp->erp_count > 0)
|
||||
eco_defer(ifp, m, erp->erp_delay);
|
||||
else {
|
||||
printf("%s: pkt failed\n", ifp->if_xname);
|
||||
m_freem(m);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ECO_SCOUT_RCVD:
|
||||
m_freem(ec->ec_scout);
|
||||
ec->ec_scout = NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ec->ec_state = ECO_IDLE;
|
||||
m_freem(ec->ec_scout);
|
||||
ec->ec_scout = NULL;
|
||||
ifp->if_start(ifp);
|
||||
}
|
||||
|
||||
@ -770,3 +847,65 @@ eco_sprintf(const u_int8_t *ea)
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Econet retry handling.
|
||||
*/
|
||||
static void
|
||||
eco_defer(struct ifnet *ifp, struct mbuf *m, int delay)
|
||||
{
|
||||
struct ecocom *ec = (struct ecocom *)ifp;
|
||||
struct eco_retry *er;
|
||||
int s;
|
||||
|
||||
MALLOC(er, struct eco_retry *, sizeof(*er), M_TEMP, M_NOWAIT);
|
||||
if (er == NULL) {
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
callout_init(&er->er_callout);
|
||||
er->er_packet = m;
|
||||
er->er_ifp = ifp;
|
||||
s = splnet();
|
||||
LIST_INSERT_HEAD(&ec->ec_retries, er, er_link);
|
||||
splx(s);
|
||||
callout_reset(&er->er_callout, delay, eco_retry, er);
|
||||
}
|
||||
|
||||
static void
|
||||
eco_retry_free(struct eco_retry *er)
|
||||
{
|
||||
int s;
|
||||
|
||||
callout_stop(&er->er_callout);
|
||||
m_freem(er->er_packet);
|
||||
s = splnet();
|
||||
LIST_REMOVE(er, er_link);
|
||||
splx(s);
|
||||
FREE(er, M_TEMP);
|
||||
}
|
||||
|
||||
static void
|
||||
eco_retry(void *arg)
|
||||
{
|
||||
struct eco_retry *er = arg;
|
||||
struct mbuf *m;
|
||||
struct ifnet *ifp;
|
||||
int s, error, len;
|
||||
|
||||
ifp = er->er_ifp;
|
||||
m = er->er_packet;
|
||||
len = m->m_pkthdr.len;
|
||||
LIST_REMOVE(er, er_link);
|
||||
s = splnet();
|
||||
IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
|
||||
if (error) {
|
||||
splx(s);
|
||||
/* XXX should defer again? */
|
||||
m_freem(m);
|
||||
}
|
||||
ifp->if_obytes += len;
|
||||
if ((ifp->if_flags & IFF_OACTIVE) == 0)
|
||||
(*ifp->if_start)(ifp);
|
||||
splx(s);
|
||||
FREE(er, M_TEMP);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user