xref: /original-bsd/sys/net/if_loop.c (revision 753853ba)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)if_loop.c	7.16 (Berkeley) 03/15/92
8  */
9 
10 /*
11  * Loopback interface driver for protocol testing and timing.
12  */
13 
14 #include "param.h"
15 #include "systm.h"
16 #include "mbuf.h"
17 #include "socket.h"
18 #include "errno.h"
19 #include "ioctl.h"
20 #include "machine/cpu.h"
21 
22 #include "if.h"
23 #include "if_types.h"
24 #include "netisr.h"
25 #include "route.h"
26 
27 #ifdef	INET
28 #include "netinet/in.h"
29 #include "netinet/in_systm.h"
30 #include "netinet/in_var.h"
31 #include "netinet/ip.h"
32 #endif
33 
34 #ifdef NS
35 #include "netns/ns.h"
36 #include "netns/ns_if.h"
37 #endif
38 
39 #ifdef ISO
40 #include "netiso/iso.h"
41 #include "netiso/iso_var.h"
42 #endif
43 
44 #define	LOMTU	(1024+512)
45 
46 struct	ifnet loif;
47 int	looutput(), loioctl();
48 
49 loattach()
50 {
51 	register struct ifnet *ifp = &loif;
52 
53 	ifp->if_name = "lo";
54 	ifp->if_mtu = LOMTU;
55 	ifp->if_flags = IFF_LOOPBACK;
56 	ifp->if_ioctl = loioctl;
57 	ifp->if_output = looutput;
58 	ifp->if_type = IFT_LOOP;
59 	ifp->if_hdrlen = 0;
60 	ifp->if_addrlen = 0;
61 	if_attach(ifp);
62 }
63 
64 looutput(ifp, m, dst, rt)
65 	struct ifnet *ifp;
66 	register struct mbuf *m;
67 	struct sockaddr *dst;
68 	register struct rtentry *rt;
69 {
70 	int s, isr;
71 	register struct ifqueue *ifq = 0;
72 
73 	if ((m->m_flags & M_PKTHDR) == 0)
74 		panic("looutput no HDR");
75 	m->m_pkthdr.rcvif = ifp;
76 
77 	if (rt && rt->rt_flags & RTF_REJECT) {
78 		m_freem(m);
79 		return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
80 	}
81 	ifp->if_opackets++;
82 	ifp->if_obytes += m->m_pkthdr.len;
83 	switch (dst->sa_family) {
84 
85 #ifdef INET
86 	case AF_INET:
87 		ifq = &ipintrq;
88 		isr = NETISR_IP;
89 		break;
90 #endif
91 #ifdef NS
92 	case AF_NS:
93 		ifq = &nsintrq;
94 		isr = NETISR_NS;
95 		break;
96 #endif
97 #ifdef ISO
98 	case AF_ISO:
99 		ifq = &clnlintrq;
100 		isr = NETISR_ISO;
101 		break;
102 #endif
103 	default:
104 		printf("lo%d: can't handle af%d\n", ifp->if_unit,
105 			dst->sa_family);
106 		m_freem(m);
107 		return (EAFNOSUPPORT);
108 	}
109 	s = splimp();
110 	if (IF_QFULL(ifq)) {
111 		IF_DROP(ifq);
112 		m_freem(m);
113 		splx(s);
114 		return (ENOBUFS);
115 	}
116 	IF_ENQUEUE(ifq, m);
117 	schednetisr(isr);
118 	ifp->if_ipackets++;
119 	ifp->if_ibytes += m->m_pkthdr.len;
120 	splx(s);
121 	return (0);
122 }
123 
124 /* ARGSUSED */
125 lortrequest(cmd, rt, sa)
126 	int cmd;
127 	struct rtentry *rt;
128 	struct sockaddr *sa;
129 {
130 
131 	if (rt)
132 		rt->rt_rmx.rmx_mtu = LOMTU;
133 }
134 
135 /*
136  * Process an ioctl request.
137  */
138 /* ARGSUSED */
139 loioctl(ifp, cmd, data)
140 	register struct ifnet *ifp;
141 	int cmd;
142 	caddr_t data;
143 {
144 	register struct ifaddr *ifa;
145 	int error = 0;
146 
147 	switch (cmd) {
148 
149 	case SIOCSIFADDR:
150 		ifp->if_flags |= IFF_UP;
151 		ifa = (struct ifaddr *)data;
152 		if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO)
153 			ifa->ifa_rtrequest = lortrequest;
154 		/*
155 		 * Everything else is done at a higher level.
156 		 */
157 		break;
158 
159 	default:
160 		error = EINVAL;
161 	}
162 	return (error);
163 }
164