xref: /csrg-svn/sys/net/if_loop.c (revision 24771)
1 /*
2  * Copyright (c) 1982 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)if_loop.c	6.7 (Berkeley) 09/16/85
7  */
8 
9 /*
10  * Loopback interface driver for protocol testing and timing.
11  */
12 
13 #include "param.h"
14 #include "systm.h"
15 #include "mbuf.h"
16 #include "socket.h"
17 #include "errno.h"
18 #include "ioctl.h"
19 
20 #ifdef	BBNNET
21 #define INET
22 #endif
23 #include "../net/if.h"
24 #include "../net/netisr.h"
25 #include "../net/route.h"
26 
27 #ifdef	INET
28 #include "../netinet/in.h"
29 #include "../netinet/in_systm.h"
30 #include "../netinet/ip.h"
31 #include "../netinet/ip_var.h"
32 #endif
33 
34 #ifdef vax
35 #include "../vax/mtpr.h"
36 #endif
37 
38 #ifdef NS
39 #include "../netns/ns.h"
40 #include "../netns/ns_if.h"
41 #endif
42 
43 #define	LOMTU	(1024+512)
44 
45 struct	ifnet loif;
46 int	looutput(), loioctl();
47 
48 loattach()
49 {
50 	register struct ifnet *ifp = &loif;
51 
52 	ifp->if_name = "lo";
53 	ifp->if_mtu = LOMTU;
54 	ifp->if_ioctl = loioctl;
55 	ifp->if_output = looutput;
56 	if_attach(ifp);
57 }
58 
59 looutput(ifp, m0, dst)
60 	struct ifnet *ifp;
61 	register struct mbuf *m0;
62 	struct sockaddr *dst;
63 {
64 	int s;
65 	register struct ifqueue *ifq;
66 	struct mbuf *m;
67 
68 	/*
69 	 * Place interface pointer before the data
70 	 * for the receiving protocol.
71 	 */
72 	if (m0->m_off <= MMAXOFF &&
73 	    m0->m_off >= MMINOFF + sizeof(struct ifnet *)) {
74 		m0->m_off -= sizeof(struct ifnet *);
75 		m0->m_len += sizeof(struct ifnet *);
76 	} else {
77 		MGET(m, M_DONTWAIT, MT_HEADER);
78 		if (m == (struct mbuf *)0)
79 			return (ENOBUFS);
80 		m->m_off = MMINOFF;
81 		m->m_len = sizeof(struct ifnet *);
82 		m->m_next = m0;
83 		m0 = m;
84 	}
85 	*(mtod(m0, struct ifnet **)) = ifp;
86 	s = splimp();
87 	ifp->if_opackets++;
88 	switch (dst->sa_family) {
89 
90 #ifdef INET
91 	case AF_INET:
92 		ifq = &ipintrq;
93 		if (IF_QFULL(ifq)) {
94 			IF_DROP(ifq);
95 			m_freem(m0);
96 			splx(s);
97 			return (ENOBUFS);
98 		}
99 		IF_ENQUEUE(ifq, m0);
100 		schednetisr(NETISR_IP);
101 		break;
102 #endif
103 #ifdef NS
104 	case AF_NS:
105 		ifq = &nsintrq;
106 		if (IF_QFULL(ifq)) {
107 			IF_DROP(ifq);
108 			m_freem(m0);
109 			splx(s);
110 			return (ENOBUFS);
111 		}
112 		IF_ENQUEUE(ifq, m0);
113 		schednetisr(NETISR_NS);
114 		break;
115 #endif
116 	default:
117 		splx(s);
118 		printf("lo%d: can't handle af%d\n", ifp->if_unit,
119 			dst->sa_family);
120 		m_freem(m0);
121 		return (EAFNOSUPPORT);
122 	}
123 	ifp->if_ipackets++;
124 	splx(s);
125 	return (0);
126 }
127 
128 /*
129  * Process an ioctl request.
130  */
131 /* ARGSUSED */
132 loioctl(ifp, cmd, data)
133 	register struct ifnet *ifp;
134 	int cmd;
135 	caddr_t data;
136 {
137 	int error = 0;
138 
139 	switch (cmd) {
140 
141 	case SIOCSIFADDR:
142 		ifp->if_flags |= IFF_UP;
143 		/*
144 		 * Everything else is done at a higher level.
145 		 */
146 		break;
147 
148 	default:
149 		error = EINVAL;
150 	}
151 	return (error);
152 }
153