xref: /csrg-svn/sys/net/if_loop.c (revision 52271)
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.15 (Berkeley) 01/30/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 struct rtentry *rt;
127 struct sockaddr *sa;
128 {
129 	if (rt)
130 		rt->rt_rmx.rmx_mtu = LOMTU;
131 }
132 
133 /*
134  * Process an ioctl request.
135  */
136 /* ARGSUSED */
137 loioctl(ifp, cmd, data)
138 	register struct ifnet *ifp;
139 	int cmd;
140 	caddr_t data;
141 {
142 	register struct ifaddr *ifa;
143 	int error = 0;
144 
145 	switch (cmd) {
146 
147 	case SIOCSIFADDR:
148 		ifp->if_flags |= IFF_UP;
149 		ifa = (struct ifaddr *)data;
150 		if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO)
151 			ifa->ifa_rtrequest = lortrequest;
152 		/*
153 		 * Everything else is done at a higher level.
154 		 */
155 		break;
156 
157 	default:
158 		error = EINVAL;
159 	}
160 	return (error);
161 }
162