xref: /original-bsd/sys/net/if_ethersubr.c (revision f1324ba5)
1 /*
2  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)if_ethersubr.c	7.1 (Berkeley) 10/12/88
18  */
19 
20 #include "param.h"
21 #include "systm.h"
22 #include "malloc.h"
23 #include "mbuf.h"
24 #include "protosw.h"
25 #include "socket.h"
26 #include "ioctl.h"
27 #include "errno.h"
28 #include "syslog.h"
29 
30 #include "if.h"
31 #include "netisr.h"
32 #include "route.h"
33 #include "if_llc.h"
34 
35 #include "../machine/mtpr.h"
36 
37 #ifdef INET
38 #include "../netinet/in.h"
39 #include "../netinet/in_var.h"
40 #include "../netinet/if_ether.h"
41 #endif
42 
43 #ifdef NS
44 #include "../netns/ns.h"
45 #include "../netns/ns_if.h"
46 #endif
47 
48 u_char	etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
49 extern	struct ifnet loif;
50 
51 /*
52  * Ethernet output routine.
53  * Encapsulate a packet of type family for the local net.
54  * Use trailer local net encapsulation if enough data in first
55  * packet leaves a multiple of 512 bytes of data in remainder.
56  * Assumes that ifp is actually pointer to arpcom structure.
57  */
58 enoutput(ifp, m0, dst)
59 	register struct ifnet *ifp;
60 	struct mbuf *m0;
61 	struct sockaddr *dst;
62 {
63 	short type;
64 	int s, error = 0;
65  	u_char edst[6];
66 	struct in_addr idst;
67 	register struct mbuf *m = m0;
68 	struct mbuf *mcopy = (struct mbuf *)0;
69 	register struct ether_header *eh;
70 	int usetrailers, off;
71 #define	ac ((struct arpcom *)ifp)
72 
73 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
74 		error = ENETDOWN;
75 		goto bad;
76 	}
77 	switch (dst->sa_family) {
78 
79 #ifdef INET
80 	case AF_INET:
81 		idst = ((struct sockaddr_in *)dst)->sin_addr;
82  		if (!arpresolve(ac, m, &idst, edst, &usetrailers))
83 			return (0);	/* if not yet resolved */
84 		off = m->m_pkthdr.len - m->m_len;
85 		if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
86 		    (m->m_flags & M_EXT) == 0 &&
87 		    m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
88 			type = ETHERTYPE_TRAIL + (off>>9);
89 			m->m_data -= 2 * sizeof (u_short);
90 			m->m_len += 2 * sizeof (u_short);
91 			*mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
92 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
93 			goto gottrailertype;
94 		}
95 		type = ETHERTYPE_IP;
96 		goto gottype;
97 #endif
98 #ifdef NS
99 	case AF_NS:
100 		type = ETHERTYPE_NS;
101 		if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
102 			return(looutput(&loif, m, dst));
103  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
104 		    (caddr_t)edst, sizeof (edst));
105 		goto gottype;
106 #endif
107 #ifdef	ISO
108 	case AF_ISO: {
109 		int	ret;
110 		ret = clnp_arpresolve(&us->us_ac.ac_if, m, dst, edst);
111 		struct llc *l;
112 		if (ret <= 0) {
113 			if (ret == -1) {
114 			/* not resolved */
115 				IFDEBUG(D_ETHER)
116 					printf("unoutput: clnp packet dropped\n");
117 				ENDDEBUG
118 			}
119 			return(0);
120 		}
121 		M_PREPEND(m, 3, M_DONTWAIT);
122 		if (m == NULL) {
123 			m_freem(mm);
124 			return(0);
125 		}
126 		type = m->m_pkthdr.len;
127 		l = mtod(m, struct llc *);
128 		l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
129 		l->llc_control = LLC_UI;
130 		IFDEBUG(D_ETHER)
131 			int i;
132 			printf("unoutput: sending pkt to: ");
133 			for (i=0; i<6; i++)
134 				printf("%x ", edst[i] & 0xff);
135 			printf("\n");
136 		ENDDEBUG
137 		} goto gottype;
138 #endif	ISO
139 
140 	case AF_UNSPEC:
141 		eh = (struct ether_header *)dst->sa_data;
142  		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
143 		type = eh->ether_type;
144 		goto gottype;
145 
146 	default:
147 		printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
148 			dst->sa_family);
149 		error = EAFNOSUPPORT;
150 		goto bad;
151 	}
152 
153 gottrailertype:
154 	/*
155 	 * Packet to be sent as trailer: move first packet
156 	 * (control information) to end of chain.
157 	 */
158 	while (m->m_next)
159 		m = m->m_next;
160 	m->m_next = m0;
161 	m = m0->m_next;
162 	m0->m_next = 0;
163 
164 gottype:
165 	/*
166 	 * Add local net header.  If no space in first mbuf,
167 	 * allocate another.
168 	 */
169 	M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
170 	if (m == 0) {
171 		error = ENOBUFS;
172 		goto bad;
173 	}
174 	eh = mtod(m, struct ether_header *);
175 	type = htons((u_short)type);
176 	bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
177 		sizeof(eh->ether_type));
178  	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
179  	bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
180 	    sizeof(eh->ether_shost));
181 	if (ifp->if_flags & IFF_SIMPLEX && dst->sa_family != AF_UNSPEC &&
182 	    !bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, sizeof (edst)))
183 		mcopy = m_copy(m, 0, (int)M_COPYALL);
184 
185 	/*
186 	 * Queue message on interface, and start output if interface
187 	 * not yet active.
188 	 */
189 	s = splimp();
190 	if (IF_QFULL(&ifp->if_snd)) {
191 		IF_DROP(&ifp->if_snd);
192 		splx(s);
193 		error = ENOBUFS;
194 		goto bad;
195 	}
196 	IF_ENQUEUE(&ifp->if_snd, m);
197 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
198 		error = (*ifp->if_start)(ifp);
199 	splx(s);
200 	if (mcopy)
201 		(void) looutput(&loif, mcopy, dst);
202 	return (error);
203 
204 bad:
205 	if (mcopy)
206 		m_freem(mcopy);
207 	if (m)
208 		m_freem(m);
209 	return (error);
210 }
211 
212 /*
213  * Pull packet off interface.  Off is nonzero if packet
214  * has trailing header; we still have to drop
215  * the type and length which are at the front of any trailer data.
216  */
217 en_doproto(ifp, eh, m)
218 	struct ifnet *ifp;
219 	register struct ether_header *eh;
220 	struct mbuf *m;
221 {
222 	register struct ifqueue *inq;
223 	register struct llc *l;
224 	int s;
225 
226 	if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
227 	    sizeof(etherbroadcastaddr)) == 0)
228 		m->m_flags |= M_BCAST;
229 	else if (eh->ether_dhost[0] & 1)
230 		m->m_flags |= M_MCAST;
231 
232 	switch (eh->ether_type) {
233 #ifdef INET
234 	case ETHERTYPE_IP:
235 		schednetisr(NETISR_IP);
236 		inq = &ipintrq;
237 		break;
238 
239 	case ETHERTYPE_ARP:
240 		arpinput((struct arpcom *)ifp, m);
241 		return;
242 #endif
243 #ifdef NS
244 	case ETHERTYPE_NS:
245 		schednetisr(NETISR_NS);
246 		inq = &nsintrq;
247 		break;
248 
249 #endif
250 	default:
251 		if (eh->ether_type > 1500)
252 			goto dropanyway;
253 		l = mtod(m, struct llc *);
254 		switch (l->llc_control) {
255 		case LLC_UI:
256 		/* LLC_UI_P forbidden in class 1 service */
257 		    if ((l->llc_dsap == LLC_ISO_LSAP) &&
258 			(l->llc_ssap == LLC_ISO_LSAP)) {
259 #ifdef	ISO
260 				/* LSAP for ISO */
261 			m->m_data += 3;
262 			m->m_len -= 3;
263 			if (m->m_flags & M_PKTHDR)
264 				m->m_pkthdr.len -= 3;
265 			DEBUGF(undebug & 0x2, printf("clnp packet\n");)
266 			schednetisr(NETISR_CLNP);
267 			inq = &clnlintrq;
268 			if (IF_QFULL(inq)){
269 				DEBUGF(undebug & 0x2, printf(" qfull\n");)
270 				IF_DROP(inq);
271 				m_freem(m);
272 			} else {
273 				IF_ENQUEUE(inq, m);
274 				DEBUGF(undebug & 0x2, printf(" queued\n");)
275 			}
276 			return;
277 #endif	ISO
278 		    }
279 		    break;
280 		case LLC_XID:
281 		case LLC_XID_P:
282 		    if(m->m_len < 6)
283 			goto dropanyway;
284 		    l->llc_window = 0;
285 		    l->llc_fid = 9;
286 		    l->llc_class = 1;
287 		    l->llc_dsap = l->llc_ssap = 0;
288 		    /* Fall through to */
289 		case LLC_TEST:
290 		case LLC_TEST_P:
291 		{
292 		    struct sockaddr sa;
293 		    register struct ether_header *eh2;
294 		    int i;
295 		    u_char c = l->llc_dsap;
296 		    l->llc_dsap = l->llc_ssap;
297 		    l->llc_ssap = c;
298 		    sa.sa_family = AF_UNSPEC;
299 		    eh2 = (struct ether_header *)sa.sa_data;
300 		    for (i = 0; i < 6; i++) {
301 			eh2->ether_shost[i] = c = eh->ether_dhost[i];
302 			eh2->ether_dhost[i] =
303 				eh->ether_dhost[i] = eh->ether_shost[i];
304 			eh->ether_shost[i] = c;
305 		    }
306 		    ifp->if_output(ifp, m, &sa);
307 		    return;
308 		}
309 		dropanyway:
310 		default:
311 		    m_freem(m);
312 		    return;
313 	    }
314 	}
315 
316 	s = splimp();
317 	if (IF_QFULL(inq)) {
318 		IF_DROP(inq);
319 		m_freem(m);
320 	} else
321 		IF_ENQUEUE(inq, m);
322 	splx(s);
323 }
324 
325 /*
326  * Convert Ethernet address to printable (loggable) representation.
327  */
328 char *
329 ether_sprintf(ap)
330 	register u_char *ap;
331 {
332 	register i;
333 	static char etherbuf[18];
334 	register char *cp = etherbuf;
335 	static char digits[] = "0123456789abcdef";
336 
337 	for (i = 0; i < 6; i++) {
338 		*cp++ = digits[*ap >> 4];
339 		*cp++ = digits[*ap++ & 0xf];
340 		*cp++ = ':';
341 	}
342 	*--cp = 0;
343 	return (etherbuf);
344 }
345