xref: /csrg-svn/sys/net/if_ethersubr.c (revision 35379)
1*35379Skfall /*
2*35379Skfall  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
3*35379Skfall  * All rights reserved.
4*35379Skfall  *
5*35379Skfall  * Redistribution and use in source and binary forms are permitted
6*35379Skfall  * provided that the above copyright notice and this paragraph are
7*35379Skfall  * duplicated in all such forms and that any documentation,
8*35379Skfall  * advertising materials, and other materials related to such
9*35379Skfall  * distribution and use acknowledge that the software was developed
10*35379Skfall  * by the University of California, Berkeley.  The name of the
11*35379Skfall  * University may not be used to endorse or promote products derived
12*35379Skfall  * from this software without specific prior written permission.
13*35379Skfall  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*35379Skfall  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*35379Skfall  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*35379Skfall  *
17*35379Skfall  *	@(#)if_ethersubr.c	1.1 (Berkeley) 08/18/88
18*35379Skfall  */
19*35379Skfall 
20*35379Skfall #include "param.h"
21*35379Skfall #include "systm.h"
22*35379Skfall #include "malloc.h"
23*35379Skfall #include "mbuf.h"
24*35379Skfall #include "protosw.h"
25*35379Skfall #include "socket.h"
26*35379Skfall #include "ioctl.h"
27*35379Skfall #include "errno.h"
28*35379Skfall #include "syslog.h"
29*35379Skfall 
30*35379Skfall #include "if.h"
31*35379Skfall #include "netisr.h"
32*35379Skfall #include "route.h"
33*35379Skfall 
34*35379Skfall #include "../machine/mtpr.h"
35*35379Skfall 
36*35379Skfall #ifdef INET
37*35379Skfall #include "../netinet/in.h"
38*35379Skfall #include "../netinet/in_var.h"
39*35379Skfall #include "../netinet/if_ether.h"
40*35379Skfall #endif
41*35379Skfall 
42*35379Skfall #ifdef NS
43*35379Skfall #include "../netns/ns.h"
44*35379Skfall #include "../netns/ns_if.h"
45*35379Skfall #endif
46*35379Skfall 
47*35379Skfall u_char	etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
48*35379Skfall 
49*35379Skfall /*
50*35379Skfall  * Ethernet output routine.
51*35379Skfall  * Encapsulate a packet of type family for the local net.
52*35379Skfall  * Use trailer local net encapsulation if enough data in first
53*35379Skfall  * packet leaves a multiple of 512 bytes of data in remainder.
54*35379Skfall  * Assumes that ifp is actually pointer to arpcom structure.
55*35379Skfall  */
56*35379Skfall enoutput(ifp, m0, dst)
57*35379Skfall 	register struct ifnet *ifp;
58*35379Skfall 	struct mbuf *m0;
59*35379Skfall 	struct sockaddr *dst;
60*35379Skfall {
61*35379Skfall 	int type, s, error;
62*35379Skfall  	u_char edst[6];
63*35379Skfall 	struct in_addr idst;
64*35379Skfall 	register struct mbuf *m = m0;
65*35379Skfall 	register struct ether_header *eh;
66*35379Skfall 	register int off;
67*35379Skfall 	int usetrailers;
68*35379Skfall #define	ac ((struct arpcom *)ifp)
69*35379Skfall 
70*35379Skfall 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
71*35379Skfall 		error = ENETDOWN;
72*35379Skfall 		goto bad;
73*35379Skfall 	}
74*35379Skfall 	switch (dst->sa_family) {
75*35379Skfall 
76*35379Skfall #ifdef INET
77*35379Skfall 	case AF_INET:
78*35379Skfall 		idst = ((struct sockaddr_in *)dst)->sin_addr;
79*35379Skfall  		if (!arpresolve(ac, m, &idst, edst, &usetrailers))
80*35379Skfall 			return (0);	/* if not yet resolved */
81*35379Skfall 		off = m->m_pkthdr.len - m->m_len;
82*35379Skfall 		if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
83*35379Skfall 		    (m->m_flags & M_EXT) == 0 &&
84*35379Skfall 		    m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
85*35379Skfall 			type = ETHERTYPE_TRAIL + (off>>9);
86*35379Skfall 			m->m_data -= 2 * sizeof (u_short);
87*35379Skfall 			m->m_len += 2 * sizeof (u_short);
88*35379Skfall 			*mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
89*35379Skfall 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
90*35379Skfall 			goto gottrailertype;
91*35379Skfall 		}
92*35379Skfall 		type = ETHERTYPE_IP;
93*35379Skfall 		off = 0;
94*35379Skfall 		goto gottype;
95*35379Skfall #endif
96*35379Skfall #ifdef NS
97*35379Skfall 	case AF_NS:
98*35379Skfall 		type = ETHERTYPE_NS;
99*35379Skfall  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
100*35379Skfall 		(caddr_t)edst, sizeof (edst));
101*35379Skfall 		off = 0;
102*35379Skfall 		goto gottype;
103*35379Skfall #endif
104*35379Skfall 
105*35379Skfall 	case AF_UNSPEC:
106*35379Skfall 		eh = (struct ether_header *)dst->sa_data;
107*35379Skfall  		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
108*35379Skfall 		type = eh->ether_type;
109*35379Skfall 		goto gottype;
110*35379Skfall 
111*35379Skfall 	default:
112*35379Skfall 		printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
113*35379Skfall 			dst->sa_family);
114*35379Skfall 		error = EAFNOSUPPORT;
115*35379Skfall 		goto bad;
116*35379Skfall 	}
117*35379Skfall 
118*35379Skfall gottrailertype:
119*35379Skfall 	/*
120*35379Skfall 	 * Packet to be sent as trailer: move first packet
121*35379Skfall 	 * (control information) to end of chain.
122*35379Skfall 	 */
123*35379Skfall 	while (m->m_next)
124*35379Skfall 		m = m->m_next;
125*35379Skfall 	m->m_next = m0;
126*35379Skfall 	m = m0->m_next;
127*35379Skfall 	m0->m_next = 0;
128*35379Skfall 	m0 = m;
129*35379Skfall 
130*35379Skfall gottype:
131*35379Skfall 	/*
132*35379Skfall 	 * Add local net header.  If no space in first mbuf,
133*35379Skfall 	 * allocate another.
134*35379Skfall 	 */
135*35379Skfall 	M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
136*35379Skfall 	if (m == 0) {
137*35379Skfall 		error = ENOBUFS;
138*35379Skfall 		goto bad;
139*35379Skfall 	}
140*35379Skfall 	eh = mtod(m, struct ether_header *);
141*35379Skfall 	eh->ether_type = htons((u_short)type);
142*35379Skfall  	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
143*35379Skfall  	bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
144*35379Skfall 	    sizeof(eh->ether_shost));
145*35379Skfall 
146*35379Skfall 	/*
147*35379Skfall 	 * Queue message on interface, and start output if interface
148*35379Skfall 	 * not yet active.
149*35379Skfall 	 */
150*35379Skfall 	s = splimp();
151*35379Skfall 	if (IF_QFULL(&ifp->if_snd)) {
152*35379Skfall 		IF_DROP(&ifp->if_snd);
153*35379Skfall 		splx(s);
154*35379Skfall 		m_freem(m);
155*35379Skfall 		return (ENOBUFS);
156*35379Skfall 	}
157*35379Skfall 	IF_ENQUEUE(&ifp->if_snd, m);
158*35379Skfall 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
159*35379Skfall 		(*ifp->if_start)(ifp->if_unit);
160*35379Skfall 	splx(s);
161*35379Skfall 	return (0);
162*35379Skfall 
163*35379Skfall bad:
164*35379Skfall 	m_freem(m0);
165*35379Skfall 	return (error);
166*35379Skfall }
167*35379Skfall 
168*35379Skfall /*
169*35379Skfall  * Pull packet off interface.  Off is nonzero if packet
170*35379Skfall  * has trailing header; we still have to drop
171*35379Skfall  * the type and length which are at the front of any trailer data.
172*35379Skfall  */
173*35379Skfall en_doproto(ifp, eh, m)
174*35379Skfall 	struct ifnet *ifp;
175*35379Skfall 	register struct ether_header *eh;
176*35379Skfall 	struct mbuf *m;
177*35379Skfall {
178*35379Skfall 	register struct ifqueue *inq;
179*35379Skfall 	int s;
180*35379Skfall 
181*35379Skfall 	if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_shost,
182*35379Skfall 	    sizeof(etherbroadcastaddr)) == 0)
183*35379Skfall 		m->m_flags |= M_BCAST;
184*35379Skfall 
185*35379Skfall 	switch (eh->ether_type) {
186*35379Skfall #ifdef INET
187*35379Skfall 	case ETHERTYPE_IP:
188*35379Skfall 		schednetisr(NETISR_IP);
189*35379Skfall 		inq = &ipintrq;
190*35379Skfall 		break;
191*35379Skfall 
192*35379Skfall 	case ETHERTYPE_ARP:
193*35379Skfall 		arpinput((struct arpcom *)ifp, m);
194*35379Skfall 		return;
195*35379Skfall #endif
196*35379Skfall #ifdef NS
197*35379Skfall 	case ETHERTYPE_NS:
198*35379Skfall 		schednetisr(NETISR_NS);
199*35379Skfall 		inq = &nsintrq;
200*35379Skfall 		break;
201*35379Skfall 
202*35379Skfall #endif
203*35379Skfall 	default:
204*35379Skfall 		m_freem(m);
205*35379Skfall 		return;
206*35379Skfall 	}
207*35379Skfall 
208*35379Skfall 	s = splimp();
209*35379Skfall 	if (IF_QFULL(inq)) {
210*35379Skfall 		IF_DROP(inq);
211*35379Skfall 		m_freem(m);
212*35379Skfall 	} else
213*35379Skfall 		IF_ENQUEUE(inq, m);
214*35379Skfall 	splx(s);
215*35379Skfall }
216*35379Skfall 
217*35379Skfall /*
218*35379Skfall  * Convert Ethernet address to printable (loggable) representation.
219*35379Skfall  */
220*35379Skfall char *
221*35379Skfall ether_sprintf(ap)
222*35379Skfall 	register u_char *ap;
223*35379Skfall {
224*35379Skfall 	register i;
225*35379Skfall 	static char etherbuf[18];
226*35379Skfall 	register char *cp = etherbuf;
227*35379Skfall 	static char digits[] = "0123456789abcdef";
228*35379Skfall 
229*35379Skfall 	for (i = 0; i < 6; i++) {
230*35379Skfall 		*cp++ = digits[*ap >> 4];
231*35379Skfall 		*cp++ = digits[*ap++ & 0xf];
232*35379Skfall 		*cp++ = ':';
233*35379Skfall 	}
234*35379Skfall 	*--cp = 0;
235*35379Skfall 	return (etherbuf);
236*35379Skfall }
237