- add support for IPX (tested with mount -t nwfs and mars_nwe),

IP fast forwarding, SIOCGIFADDR, setting hardware address (not currently
enabled in cm driver), multicasts (experimental)
- add ARC_MAX_DATA, use IF_HANDOFF, remove arc_sprintf() and some unused
variables
- if_simloop logic is made more similar to ethernet
- drop not ours packets early (if we are not in promiscous mode)

Submitted by:	mark tinguely (partially)
This commit is contained in:
Max Khon 2003-01-24 01:32:20 +00:00
parent 9a03c49d6c
commit 6cdcc15976
5 changed files with 175 additions and 95 deletions

View File

@ -44,7 +44,7 @@
/* #define CMSOFTCOPY */
#define CMRETRANSMIT /**/
#undef CM_DEBUG
/* #define CM_DEBUG */
#include <sys/param.h>
#include <sys/systm.h>
@ -346,7 +346,7 @@ cm_attach(sc, unit)
#endif
}
if_printf(ifp, "link addr 0x%02x(%d)\n", linkaddress, linkaddress);
if_printf(ifp, "link addr 0x%02x (%d)\n", linkaddress, linkaddress);
return 0;
}
@ -531,7 +531,7 @@ cm_start(ifp)
if (m->m_len < 2)
m = m_pullup(m, 2);
#endif
cm_ram_ptr = buffer*512;
cm_ram_ptr = buffer * 512;
if (m == 0)
return;
@ -666,7 +666,7 @@ cm_srint(vsc)
* (2*sizeof(ulong) - CM_HDRNEWLEN)), packet type dependent.
*/
cm_ram_ptr = buffer*512;
cm_ram_ptr = buffer * 512;
offset = GETMEM(cm_ram_ptr + 2);
if (offset)
len = 256 - offset;
@ -844,7 +844,7 @@ cmintr(arg)
return;
do {
#if defined(CM_DEBUG) && (CM_DEBUG>1)
#if defined(CM_DEBUG) && (CM_DEBUG > 1)
if_printf(ifp, "intr: status 0x%02x, intmask 0x%02x\n",
isr, sc->sc_intmask);
#endif
@ -905,7 +905,7 @@ cmintr(arg)
buffer = sc->sc_rx_act;
/* look if buffer is marked invalid: */
if (GETMEM(buffer*512) == 0) {
if (GETMEM(buffer * 512) == 0) {
/*
* invalid marked buffer (or illegally
* configured sender)
@ -959,7 +959,7 @@ cmintr(arg)
isr = GETREG(CMSTAT);
maskedisr = isr & sc->sc_intmask;
} while (maskedisr);
#if defined(CM_DEBUG) && (CM_DEBUG>1)
#if defined(CM_DEBUG) && (CM_DEBUG > 1)
if_printf(ifp, "intr (exit): status 0x%02x, intmask 0x%02x\n",
isr, sc->sc_intmask);
#endif
@ -1008,6 +1008,7 @@ cm_ioctl(ifp, command, data)
switch (command) {
case SIOCSIFADDR:
case SIOCGIFADDR:
case SIOCADDMULTI:
case SIOCDELMULTI:
case SIOCSIFMTU:

View File

@ -4,7 +4,7 @@
KMOD= arcnet
SRCS= if_arcsubr.c
SRCS+= opt_inet.h opt_inet6.h
SRCS+= opt_inet.h opt_inet6.h opt_ipx.h
EXPORT_SYMS= arc_frag_init \
arc_frag_next \
@ -19,4 +19,7 @@ EXPORT_SYMS= arc_frag_init \
opt_inet.h opt_inet6.h:
echo "#define INET 1" > ${.TARGET}
opt_ipx.h:
echo "#define IPX 1" > ${.TARGET}
.include <bsd.kmod.mk>

View File

@ -1950,6 +1950,8 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
case IFT_ISO88025:
case IFT_L2VLAN:
bcopy(lladdr, ((struct arpcom *)ifp->if_softc)->ac_enaddr, len);
/* FALLTHROUGH */
case IFT_ARCNET:
bcopy(lladdr, LLADDR(sdl), len);
break;
default:

View File

@ -77,12 +77,12 @@ struct arc_header {
#define ARC_HDRNEWLEN 6
#define ARC_HDRNEWLEN_EXC 10
/* these lengths are data link layer length - 2*ARC_ADDR_LEN */
/* these lengths are data link layer length - 2 * ARC_ADDR_LEN */
#define ARC_MIN_LEN 1
#define ARC_MIN_FORBID_LEN 254
#define ARC_MAX_FORBID_LEN 256
#define ARC_MAX_LEN 508
#define ARC_MAX_DATA 504
/* RFC 1051 */
#define ARCTYPE_IP_OLD 240 /* IP protocol */
@ -134,7 +134,6 @@ extern int arc_ipmtu; /* XXX new ip only, no RFC 1051! */
void arc_ifattach(struct ifnet *, u_int8_t);
void arc_ifdetach(struct ifnet *);
void arc_storelladdr(struct ifnet *, u_int8_t);
char *arc_sprintf(u_int8_t *);
int arc_isphds(int);
void arc_input(struct ifnet *, struct mbuf *);
int arc_output(struct ifnet *, struct mbuf *,

View File

@ -40,6 +40,7 @@
*/
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipx.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -73,16 +74,24 @@
#include <netinet6/nd6.h>
#endif
#ifdef IPX
#include <netipx/ipx.h>
#include <netipx/ipx_if.h>
#endif
MODULE_VERSION(arcnet, 1);
#define ARCNET_ALLOW_BROKEN_ARP
static struct mbuf *arc_defrag(struct ifnet *, struct mbuf *);
static int arc_resolvemulti(struct ifnet *, struct sockaddr **,
struct sockaddr *);
u_int8_t arcbroadcastaddr = 0;
#define senderr(e) { error = (e); goto bad;}
#define SIN(s) ((struct sockaddr_in *)s)
#define SIN(s) ((struct sockaddr_in *)s)
#define SIPX(s) ((struct sockaddr_ipx *)s)
/*
* ARCnet output routine.
@ -96,23 +105,18 @@ arc_output(ifp, m, dst, rt0)
struct sockaddr *dst;
struct rtentry *rt0;
{
struct mbuf *mcopy;
struct rtentry *rt;
struct arccom *ac;
struct arc_header *ah;
struct arphdr *arph;
int error;
u_int8_t atype, adst;
#if __FreeBSD_version < 500000
int s;
#endif
int loop_copy = 0;
if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
return(ENETDOWN); /* m, m1 aren't initialized yet */
error = 0;
ac = (struct arccom *)ifp;
mcopy = NULL;
if ((rt = rt0)) {
if ((rt->rt_flags & RTF_UP) == 0) {
@ -151,10 +155,6 @@ arc_output(ifp, m, dst, rt0)
else if (!arpresolve(ifp, rt, m, dst, &adst, rt0))
return 0; /* not resolved yet */
/* If broadcasting on a simplex interface, loopback a copy */
if ((m->m_flags & (M_BCAST|M_MCAST)) &&
(ifp->if_flags & IFF_SIMPLEX))
mcopy = m_copy(m, 0, (int)M_COPYALL);
atype = (ifp->if_flags & IFF_LINK0) ?
ARCTYPE_IP_OLD : ARCTYPE_IP;
break;
@ -171,8 +171,17 @@ arc_output(ifp, m, dst, rt0)
atype = ARCTYPE_INET6;
break;
#endif
#ifdef IPX
case AF_IPX:
adst = SIPX(dst)->sipx_addr.x_host.c_host[5];
atype = ARCTYPE_IPX;
if (adst == 0xff)
adst = arcbroadcastaddr;
break;
#endif
case AF_UNSPEC:
loop_copy = -1;
ah = (struct arc_header *)dst->sa_data;
adst = ah->arc_dhost;
atype = ah->arc_type;
@ -188,9 +197,8 @@ arc_output(ifp, m, dst, rt0)
* However, e.g., AmiTCP 3.0Beta used it... we make this
* switchable for emergency cases. Not perfect, but...
*/
arph = mtod(m, struct arphdr *);
if (ifp->if_flags & IFF_LINK2)
arph->ar_pro = atype - 1;
mtod(m, struct arphdr *)->ar_pro = atype - 1;
#endif
}
break;
@ -200,9 +208,6 @@ arc_output(ifp, m, dst, rt0)
senderr(EAFNOSUPPORT);
}
if (mcopy)
(void) if_simloop(ifp, mcopy, dst->sa_family, 0);
M_PREPEND(m, ARC_HDRLEN, M_NOWAIT);
if (m == 0)
senderr(ENOBUFS);
@ -211,31 +216,23 @@ arc_output(ifp, m, dst, rt0)
ah->arc_dhost = adst;
ah->arc_shost = *IF_LLADDR(ifp);
if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
(void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN);
} else if (ah->arc_dhost == ah->arc_shost) {
(void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN);
return (0); /* XXX */
}
}
BPF_MTAP(ifp, m);
#if __FreeBSD_version < 500000
s = splimp();
/*
* Queue message on interface, and start output if interface
* not yet active.
*/
if (IF_QFULL(&ifp->if_snd)) {
IF_DROP(&ifp->if_snd);
splx(s);
senderr(ENOBUFS);
}
ifp->if_obytes += m->m_pkthdr.len;
IF_ENQUEUE(&ifp->if_snd, m);
if ((ifp->if_flags & IFF_OACTIVE) == 0)
(*ifp->if_start)(ifp);
splx(s);
#else
if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) {
m = 0;
senderr(ENOBUFS);
}
#endif
return (error);
@ -277,7 +274,7 @@ arc_frag_next(ifp)
return m;
++ac->ac_seqid; /* make the seqid unique */
tfrags = (m->m_pkthdr.len + 503) / 504;
tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA;
ac->fsflag = 2 * tfrags - 3;
ac->sflag = 0;
ac->rsflag = ac->fsflag;
@ -292,7 +289,7 @@ arc_frag_next(ifp)
/* split out next fragment and return it */
if (ac->sflag < ac->fsflag) {
/* we CAN'T have short packets here */
ac->curr_frag = m_split(m, 504, M_NOWAIT);
ac->curr_frag = m_split(m, ARC_MAX_DATA, M_NOWAIT);
if (ac->curr_frag == 0) {
m_freem(m);
return 0;
@ -523,12 +520,6 @@ arc_input(ifp, m)
struct arc_header *ah;
struct ifqueue *inq;
u_int8_t atype;
#ifdef INET
struct arphdr *arph;
#endif
#if __FreeBSD_version < 500000
int s;
#endif
if ((ifp->if_flags & IFF_UP) == 0) {
m_freem(m);
@ -543,10 +534,17 @@ arc_input(ifp, m)
BPF_MTAP(ifp, m);
ah = mtod(m, struct arc_header *);
/* does this belong to us? */
if ((ifp->if_flags & IFF_PROMISC) != 0
&& ah->arc_dhost != arcbroadcastaddr
&& ah->arc_dhost != *IF_LLADDR(ifp)) {
m_freem(m);
return;
}
ifp->if_ibytes += m->m_pkthdr.len;
if (arcbroadcastaddr == ah->arc_dhost) {
if (ah->arc_dhost == arcbroadcastaddr) {
m->m_flags |= M_BCAST|M_MCAST;
ifp->if_imcasts++;
}
@ -556,12 +554,16 @@ arc_input(ifp, m)
#ifdef INET
case ARCTYPE_IP:
m_adj(m, ARC_HDRNEWLEN);
if (ipflow_fastforward(m))
return;
schednetisr(NETISR_IP);
inq = &ipintrq;
break;
case ARCTYPE_IP_OLD:
m_adj(m, ARC_HDRLEN);
if (ipflow_fastforward(m))
return;
schednetisr(NETISR_IP);
inq = &ipintrq;
break;
@ -589,7 +591,6 @@ arc_input(ifp, m)
m_adj(m, ARC_HDRLEN);
schednetisr(NETISR_ARP);
inq = &arpintrq;
arph = mtod(m, struct arphdr *);
#ifdef ARCNET_ALLOW_BROKEN_ARP
mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
#endif
@ -601,40 +602,20 @@ arc_input(ifp, m)
schednetisr(NETISR_IPV6);
inq = &ip6intrq;
break;
#endif
#ifdef IPX
case ARCTYPE_IPX:
m_adj(m, ARC_HDRNEWLEN);
schednetisr(NETISR_IPX);
inq = &ipxintrq;
break;
#endif
default:
m_freem(m);
return;
}
#if __FreeBSD_version < 500000
s = splimp();
if (IF_QFULL(inq)) {
IF_DROP(inq);
m_freem(m);
} else
IF_ENQUEUE(inq, m);
splx(s);
#else
IF_HANDOFF(inq, m, NULL);
#endif
}
/*
* Convert Arcnet address to printable (loggable) representation.
*/
static char digits[] = "0123456789abcdef";
char *
arc_sprintf(ap)
u_int8_t *ap;
{
static char arcbuf[3];
char *cp = arcbuf;
*cp++ = digits[*ap >> 4];
*cp++ = digits[*ap++ & 0xf];
*cp = 0;
return (arcbuf);
}
/*
@ -665,6 +646,7 @@ arc_ifattach(ifp, lla)
ifp->if_addrlen = 1;
ifp->if_hdrlen = ARC_HDRLEN;
ifp->if_mtu = 1500;
ifp->if_resolvemulti = arc_resolvemulti;
if (ifp->if_baudrate == 0)
ifp->if_baudrate = 2500000;
#if __FreeBSD_version < 500000
@ -721,6 +703,26 @@ arc_ioctl(ifp, command, data)
ifp->if_init(ifp->if_softc); /* before arpwhohas */
arp_ifinit(ifp, ifa);
break;
#endif
#ifdef IPX
/*
* XXX This code is probably wrong
*/
case AF_IPX:
{
struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
if (ipx_nullhost(*ina))
ina->x_host.c_host[5] = *IF_LLADDR(ifp);
else
arc_storelladdr(ifp, ina->x_host.c_host[5]);
/*
* Set new address
*/
ifp->if_init(ifp->if_softc);
break;
}
#endif
default:
ifp->if_init(ifp->if_softc);
@ -728,6 +730,16 @@ arc_ioctl(ifp, command, data)
}
break;
case SIOCGIFADDR:
{
struct sockaddr *sa;
sa = (struct sockaddr *) &ifr->ifr_data;
bcopy(IF_LLADDR(ifp),
(caddr_t) sa->sa_data, ARC_ADDR_LEN);
}
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
if (ifr == NULL)
@ -757,19 +769,82 @@ arc_ioctl(ifp, command, data)
else
ifp->if_mtu = ifr->ifr_mtu;
break;
#if 0
case SIOCGIFADDR:
{
struct sockaddr *sa;
sa = (struct sockaddr *) & ifr->ifr_data;
bcopy(IFP2AC(ifp)->ac_enaddr,
(caddr_t) sa->sa_data, ETHER_ADDR_LEN);
}
break;
#endif
}
return (error);
}
/* based on ether_resolvemulti() */
int
arc_resolvemulti(ifp, llsa, sa)
struct ifnet *ifp;
struct sockaddr **llsa;
struct sockaddr *sa;
{
struct sockaddr_dl *sdl;
struct sockaddr_in *sin;
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
switch(sa->sa_family) {
case AF_LINK:
/*
* No mapping needed. Just check that it's a valid MC address.
*/
sdl = (struct sockaddr_dl *)sa;
if (*LLADDR(sdl) != arcbroadcastaddr)
return EADDRNOTAVAIL;
*llsa = 0;
return 0;
#ifdef INET
case AF_INET:
sin = (struct sockaddr_in *)sa;
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
return EADDRNOTAVAIL;
MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
M_ZERO);
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_ARCNET;
sdl->sdl_alen = ARC_ADDR_LEN;
*LLADDR(sdl) = 0;
*llsa = (struct sockaddr *)sdl;
return 0;
#endif
#ifdef INET6
case AF_INET6:
sin6 = (struct sockaddr_in6 *)sa;
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
/*
* An IP6 address of 0 means listen to all
* of the Ethernet multicast address used for IP6.
* (This is used for multicast routers.)
*/
ifp->if_flags |= IFF_ALLMULTI;
*llsa = 0;
return 0;
}
if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
return EADDRNOTAVAIL;
MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
M_ZERO);
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_ARCNET;
sdl->sdl_alen = ARC_ADDR_LEN;
*LLADDR(sdl) = 0;
*llsa = (struct sockaddr *)sdl;
return 0;
#endif
default:
/*
* Well, the text isn't quite right, but it's the name
* that counts...
*/
return EAFNOSUPPORT;
}
}