1
0
Files
irix-657m-src/irix/kern/bsd/net/if_loop.c
2022-09-29 17:59:04 +03:00

294 lines
6.7 KiB
C

/*
* Copyright (c) 1982, 1986 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* @(#)if_loop.c 7.4 (Berkeley) 6/27/88 plus MULTICAST 1.1
*/
/*
* Loopback interface driver for protocol testing and timing.
*/
#include "tcp-param.h"
#include "sys/param.h"
#include "sys/debug.h"
#include "sys/errno.h"
#include "sys/sema.h"
#include "sys/hashing.h"
#include "sys/mbuf.h"
#include "sys/sbd.h"
#include "sys/socket.h"
#include "sys/socketvar.h"
#include "sys/systm.h"
#include "raw.h"
#include "soioctl.h"
#include "bstring.h"
#include <net/if.h>
#include <net/netisr.h>
#include <net/route.h>
#include <net/if_types.h>
#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#ifdef INET6
#include <netinet/in6_var.h>
#include <netinet/ip6.h>
#include <netinet/if_ndp6.h>
#endif
#endif
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
#endif
#ifdef sgi
extern int lomtu;
#else
#define LOMTU (1024+512)
#endif
struct ifnet loif;
#ifdef sgi
int looutput(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
struct rtentry *);
int loioctl(struct ifnet *ifp, int cmd, caddr_t data);
#else
int looutput(), loioctl();
#endif
#ifdef sgi
/*
* For snooping purposes, pretend lo0 provides an encapsulation consisting
* a socket address family (loop_family).
*/
static struct rawif lorawif; /* loopback raw interface */
struct loopbufhead {
struct ifheader ifh; /* interface queue header */
struct snoopheader snoop; /* snoop protocol header */
__int32_t filler; /* align start of this structure */
struct loopheader loop; /* loopback header */
};
#endif
void
loattach(void)
{
register struct ifnet *ifp = &loif;
ifp->if_name = "lo";
ifp->if_mtu = lomtu;
ifp->if_type = IFT_LOOP;
ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST | IFF_CKSUM;
ifp->if_ioctl = (int (*)(struct ifnet *, int , void *))loioctl;
ifp->if_output = looutput;
#ifdef INET6
ifp->if_ndtype = IFND6_LOOP;
#endif
if_attach(ifp);
rawif_attach(&lorawif, ifp,
(caddr_t) 0, (caddr_t) 0, 0,
sizeof(struct loopheader), 0, 0);
}
/* ARGSUSED */
int
looutput(struct ifnet *ifp,
register struct mbuf *m0,
struct sockaddr *dst,
struct rtentry *rte)
{
struct mbuf *m;
int data_len;
int pad;
#ifdef INET6
int af;
#endif
ASSERT(IFNET_ISLOCKED(ifp) || ifp->if_flags & IFF_LOOPBACK);
/*
* Handle raw output, which puts the true destination address family
* in a loopheader at the beginning of the user's buffer.
*/
if (dst->sa_family == AF_RAW) {
if (m0->m_len < sizeof(struct loopheader)) {
m_freem(m0);
return EIO;
}
dst->sa_family = mtod(m0, struct loopheader *)->loop_family;
M_ADJ(m0, sizeof(struct loopheader));
}
data_len = m_length(m0); /* close enough */
/*
* Tell everyone all checksums are good.
*/
m0->m_flags |= M_CKSUMMED;
/*
* Make sure that the data is doubleword aligned, so compute
* a number of bytes to add to the header if we reuse the mbuf.
* This ought to be 8-mtod(...), but be sloppy and save two
* instructions.
*/
pad = (mtod(m0, __psint_t) & 0x7) + sizeof(struct loopbufhead);
/*
* Prepend an ifheader containing the interface pointer and enough
* space for a snoopheader and loopheader.
*/
if (!M_HASCL(m0)
&& m0->m_off >= MMINOFF + pad) {
M_ADJ(m0, -pad);
IF_INITHEADER(mtod(m0, caddr_t), ifp, pad);
} else {
pad = sizeof(struct loopbufhead);
MGET(m, M_DONTWAIT, MT_HEADER);
if (m == 0) {
m_freem(m0);
return ENOBUFS;
}
M_INITIFHEADER(m, ifp, pad);
m->m_next = m0;
m0 = m;
}
ASSERT(!(mtod(m0, __psint_t) & 0x7));
/*
* If there are any snoopers, provide SNOOP_FILTERLEN contiguous words
* of loopheader and data for filtering.
*/
IFNET_LOCK(&loif); /* until needs to support many loopback */
if (RAWIF_SNOOPING(&lorawif)) {
struct loopbufhead *lbh;
union {
struct loopheader loop;
__uint32_t s[SNOOP_FILTERLEN];
u_char c[1];
} buf;
int len, cnt;
caddr_t hp;
/*
* Set the loopback "MAC header" only here since it
* is used only when snooping.
*/
lbh = (struct loopbufhead *)&mtod(m0, caddr_t)[pad] - 1;
lbh->loop.loop_family = dst->sa_family;
lbh->loop.loop_spare = 0;
if (m0->m_len >= (sizeof(*lbh)+pad
- sizeof(lbh->loop) + sizeof(buf))) {
hp = (caddr_t) &lbh->loop; /* use m0 as buf */
} else {
hp = (caddr_t)&buf;
buf.loop = lbh->loop;
len = sizeof(buf) - sizeof(buf.loop);
cnt = m_datacopy(m0, pad, len, (caddr_t)(&buf.loop+1));
if (cnt < len)
bzero(&buf.c[cnt], len - cnt);
}
snoop_input(&lorawif, 0, hp, m0, data_len);
}
ifp->if_opackets++;
ifp->if_obytes += data_len;
ifp->if_ibytes += data_len;
#ifdef INET6
af = ((struct sockaddr_new *)dst)->sa_family;
if (af == AF_INET || af == AF_INET6) {
network_input(m0, af, 0);
#else
if (dst->sa_family == AF_INET) {
network_input(m0, dst->sa_family, 0);
#endif
} else if (RAWIF_DRAINING(&lorawif)) {
drain_input(&lorawif, dst->sa_family, (caddr_t) 0, m0);
} else {
IFNET_UNLOCK(&loif);
#ifdef DEBUG
printf("lo%d: can't handle address family %d\n",
ifp->if_unit, dst->sa_family);
#endif
m_freem(m0);
return (EAFNOSUPPORT);
}
ifp->if_ipackets++;
IFNET_UNLOCK(&loif);
return (0);
}
/*
* Process an ioctl request.
*/
/* ARGSUSED */
#ifdef sgi
int
loioctl(register struct ifnet *ifp,
int cmd,
caddr_t data)
#else
loioctl(ifp, cmd, data)
register struct ifnet *ifp;
int cmd;
caddr_t data;
#endif
{
#ifdef sgi /* MULTICAST */
register struct sockaddr *sa = (struct sockaddr *)data;
#endif /* MULTICAST */
int error = 0;
ASSERT(IFNET_ISLOCKED(ifp));
switch (cmd) {
case SIOCSIFADDR:
ifp->if_flags |= IFF_UP|IFF_RUNNING;
/*
* Everything else is done at a higher level.
*/
#ifdef sgi
/* allow MTU to be tuned without rebooting */
ifp->if_mtu = lomtu;
#endif
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
switch (sa->sa_family) {
#ifdef INET6
case AF_INET6:
#endif
case AF_INET:
break;
default:
error = EAFNOSUPPORT;
break;
}
break;
default:
error = EINVAL;
}
return (error);
}