freebsd-dev/sys/dev/pdq/pdq_ifsubr.c
Poul-Henning Kamp 46783fb897 Remove NBPF conditionality of bpf calls in most of our network drivers.
This means that we will not have to have a bpf and a non-bpf version
of our driver modules.

This does not open any security hole, because the bpf core isn't loadable

The drivers left unchanged are the "cross platform" drivers where the respective
maintainers are urged to DTRT, whatever that may be.

Add a couple of missing FreeBSD tags.
1999-09-25 12:06:01 +00:00

382 lines
8.6 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*-
* Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software withough specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*
*/
/*
* DEC PDQ FDDI Controller; code for BSD derived operating systems
*
* This module provide bus independent BSD specific O/S functions.
* (ie. it provides an ifnet interface to the rest of the system)
*/
#include "opt_inet.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#if defined(__bsdi__) || defined(__NetBSD__)
#include <sys/device.h>
#endif
#include <net/if.h>
#include <net/if_dl.h>
#include <net/bpf.h>
#if defined(__FreeBSD__)
#ifdef INET
#include <netinet/in.h>
#include <netinet/if_ether.h>
#endif
#include <netinet/if_fddi.h>
#else
#include <net/if_fddi.h>
#endif
#if defined(__bsdi__)
#include <i386/isa/isavar.h>
#endif
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
#endif
#if defined(__FreeBSD__)
#include <dev/pdq/pdqvar.h>
#include <dev/pdq/pdqreg.h>
#else
#include "pdqvar.h"
#include "pdqreg.h"
#endif
#if defined(__bsdi__) && _BSDI_VERSION < 199506 /* XXX */
static void
arp_ifinit(
struct arpcom *ac,
struct ifaddr *ifa)
{
sc->sc_ac.ac_ipaddr = IA_SIN(ifa)->sin_addr;
arpwhohas(&sc->sc_ac, &IA_SIN(ifa)->sin_addr);
#if _BSDI_VERSION >= 199401
ifa->ifa_rtrequest = arp_rtrequest;
ifa->ifa_flags |= RTF_CLONING;
#endif
#endif
void
pdq_ifinit(
pdq_softc_t *sc)
{
if (sc->sc_if.if_flags & IFF_UP) {
sc->sc_if.if_flags |= IFF_RUNNING;
if (sc->sc_if.if_flags & IFF_PROMISC) {
sc->sc_pdq->pdq_flags |= PDQ_PROMISC;
} else {
sc->sc_pdq->pdq_flags &= ~PDQ_PROMISC;
}
if (sc->sc_if.if_flags & IFF_ALLMULTI) {
sc->sc_pdq->pdq_flags |= PDQ_ALLMULTI;
} else {
sc->sc_pdq->pdq_flags &= ~PDQ_ALLMULTI;
}
if (sc->sc_if.if_flags & IFF_LINK1) {
sc->sc_pdq->pdq_flags |= PDQ_PASS_SMT;
} else {
sc->sc_pdq->pdq_flags &= ~PDQ_PASS_SMT;
}
sc->sc_pdq->pdq_flags |= PDQ_RUNNING;
pdq_run(sc->sc_pdq);
} else {
sc->sc_if.if_flags &= ~IFF_RUNNING;
sc->sc_pdq->pdq_flags &= ~PDQ_RUNNING;
pdq_stop(sc->sc_pdq);
}
}
void
pdq_ifwatchdog(
struct ifnet *ifp)
{
/*
* No progress was made on the transmit queue for PDQ_OS_TX_TRANSMIT
* seconds. Remove all queued packets.
*/
ifp->if_flags &= ~IFF_OACTIVE;
ifp->if_timer = 0;
for (;;) {
struct mbuf *m;
IF_DEQUEUE(&ifp->if_snd, m);
if (m == NULL)
return;
m_freem(m);
}
}
ifnet_ret_t
pdq_ifstart(
struct ifnet *ifp)
{
pdq_softc_t *sc = (pdq_softc_t *) ((caddr_t) ifp - offsetof(pdq_softc_t, sc_ac.ac_if));
struct ifqueue *ifq = &ifp->if_snd;
struct mbuf *m;
int tx = 0;
if ((ifp->if_flags & IFF_RUNNING) == 0)
return;
if (sc->sc_if.if_timer == 0)
sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
if ((sc->sc_pdq->pdq_flags & PDQ_TXOK) == 0) {
sc->sc_if.if_flags |= IFF_OACTIVE;
return;
}
for (;; tx = 1) {
IF_DEQUEUE(ifq, m);
if (m == NULL)
break;
if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE) {
ifp->if_flags |= IFF_OACTIVE;
IF_PREPEND(ifq, m);
break;
}
}
if (tx)
PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq);
}
void
pdq_os_receive_pdu(
pdq_t *pdq,
struct mbuf *m,
size_t pktlen)
{
pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
struct fddi_header *fh = mtod(m, struct fddi_header *);
sc->sc_if.if_ipackets++;
if (sc->sc_bpf != NULL)
PDQ_BPF_MTAP(sc, m);
if ((fh->fddi_fc & (FDDIFC_L|FDDIFC_F)) != FDDIFC_LLC_ASYNC) {
m_freem(m);
return;
}
m->m_data += sizeof(struct fddi_header);
m->m_len -= sizeof(struct fddi_header);
m->m_pkthdr.len = pktlen - sizeof(struct fddi_header);
m->m_pkthdr.rcvif = &sc->sc_if;
fddi_input(&sc->sc_if, fh, m);
}
void
pdq_os_restart_transmitter(
pdq_t *pdq)
{
pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
sc->sc_if.if_flags &= ~IFF_OACTIVE;
if (sc->sc_if.if_snd.ifq_head != NULL) {
sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
pdq_ifstart(&sc->sc_if);
} else {
sc->sc_if.if_timer = 0;
}
}
void
pdq_os_transmit_done(
pdq_t *pdq,
struct mbuf *m)
{
pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
if (sc->sc_bpf != NULL)
PDQ_BPF_MTAP(sc, m);
m_freem(m);
sc->sc_if.if_opackets++;
}
void
pdq_os_addr_fill(
pdq_t *pdq,
pdq_lanaddr_t *addr,
size_t num_addrs)
{
pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
struct ifmultiaddr *ifma;
for (ifma = sc->sc_if.if_multiaddrs.lh_first; ifma && num_addrs > 0;
ifma = ifma->ifma_link.le_next) {
char *mcaddr;
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
mcaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
((u_short *) addr->lanaddr_bytes)[0] = ((u_short *) mcaddr)[0];
((u_short *) addr->lanaddr_bytes)[1] = ((u_short *) mcaddr)[1];
((u_short *) addr->lanaddr_bytes)[2] = ((u_short *) mcaddr)[2];
addr++;
num_addrs--;
}
}
int
pdq_ifioctl(
struct ifnet *ifp,
ioctl_cmd_t cmd,
caddr_t data)
{
pdq_softc_t *sc = (pdq_softc_t *) ((caddr_t) ifp - offsetof(pdq_softc_t, sc_ac.ac_if));
int s, error = 0;
s = splimp();
switch (cmd) {
case SIOCSIFADDR: {
struct ifaddr *ifa = (struct ifaddr *)data;
ifp->if_flags |= IFF_UP;
switch(ifa->ifa_addr->sa_family) {
#if defined(INET)
case AF_INET: {
pdq_ifinit(sc);
arp_ifinit(&sc->sc_ac, ifa);
break;
}
#endif /* INET */
#if defined(NS)
/* This magic copied from if_is.c; I don't use XNS,
* so I have no way of telling if this actually
* works or not.
*/
case AF_NS: {
struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
if (ns_nullhost(*ina)) {
ina->x_host = *(union ns_host *)(sc->sc_ac.ac_enaddr);
} else {
ifp->if_flags &= ~IFF_RUNNING;
bcopy((caddr_t)ina->x_host.c_host,
(caddr_t)sc->sc_ac.ac_enaddr,
sizeof sc->sc_ac.ac_enaddr);
}
pdq_ifinit(sc);
break;
}
#endif /* NS */
default: {
pdq_ifinit(sc);
break;
}
}
break;
}
case SIOCGIFADDR: {
struct ifreq *ifr = (struct ifreq *)data;
bcopy((caddr_t) sc->sc_ac.ac_enaddr,
(caddr_t) ((struct sockaddr *)&ifr->ifr_data)->sa_data,
6);
break;
}
case SIOCSIFFLAGS: {
pdq_ifinit(sc);
break;
}
case SIOCADDMULTI:
case SIOCDELMULTI:
/*
* Update multicast listeners
*/
if (sc->sc_if.if_flags & IFF_RUNNING)
pdq_run(sc->sc_pdq);
error = 0;
break;
#if defined(SIOCSIFMTU)
#if !defined(ifr_mtu)
#define ifr_mtu ifr_metric
#endif
case SIOCSIFMTU: {
struct ifreq *ifr = (struct ifreq *)data;
/*
* Set the interface MTU.
*/
if (ifr->ifr_mtu > FDDIMTU) {
error = EINVAL;
break;
}
ifp->if_mtu = ifr->ifr_mtu;
break;
}
#endif /* SIOCSIFMTU */
default: {
error = EINVAL;
break;
}
}
splx(s);
return error;
}
#ifndef IFF_NOTRAILERS
#define IFF_NOTRAILERS 0
#endif
void
pdq_ifattach(
pdq_softc_t *sc,
ifnet_ret_t (*ifwatchdog)(int unit))
{
struct ifnet *ifp = &sc->sc_if;
ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
#if (defined(__FreeBSD__) && BSD >= 199506) || defined(__NetBSD__)
ifp->if_watchdog = pdq_ifwatchdog;
#else
ifp->if_watchdog = ifwatchdog;
#endif
ifp->if_ioctl = pdq_ifioctl;
ifp->if_output = fddi_output;
ifp->if_start = pdq_ifstart;
#warning "Implement fddi_resolvemulti!"
/* ifp->if_resolvemulti = ether_resolvemulti; XXX */
if_attach(ifp);
fddi_ifattach(ifp);
PDQ_BPFATTACH(sc, DLT_FDDI, sizeof(struct fddi_header));
}