This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sys / net / if_ethersubr.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1982, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)if_ethersubr.c 7.13 (Berkeley) 4/20/91
34 */
35
36#include "param.h"
37#include "systm.h"
38#include "kernel.h"
39#include "malloc.h"
40#include "mbuf.h"
41#include "protosw.h"
42#include "socket.h"
43#include "ioctl.h"
44#include "errno.h"
45#include "syslog.h"
46
47#include "if.h"
48#include "netisr.h"
49#include "route.h"
50#include "if_llc.h"
51#include "if_dl.h"
52
53#include "machine/mtpr.h"
54
55#ifdef INET
56#include "../netinet/in.h"
57#include "../netinet/in_var.h"
58#endif
59#include "../netinet/if_ether.h"
60
61#ifdef NS
62#include "../netns/ns.h"
63#include "../netns/ns_if.h"
64#endif
65
66#ifdef ISO
67#include "../netiso/argo_debug.h"
68#include "../netiso/iso.h"
69#include "../netiso/iso_var.h"
70#include "../netiso/iso_snpac.h"
71#endif
72
73u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
74extern struct ifnet loif;
75
76/*
77 * Ethernet output routine.
78 * Encapsulate a packet of type family for the local net.
79 * Use trailer local net encapsulation if enough data in first
80 * packet leaves a multiple of 512 bytes of data in remainder.
81 * Assumes that ifp is actually pointer to arpcom structure.
82 */
83ether_output(ifp, m0, dst, rt)
84 register struct ifnet *ifp;
85 struct mbuf *m0;
86 struct sockaddr *dst;
87 struct rtentry *rt;
88{
89 short type;
90 int s, error = 0;
91 u_char edst[6];
92 struct in_addr idst;
93 register struct mbuf *m = m0;
94 struct mbuf *mcopy = (struct mbuf *)0;
95 register struct ether_header *eh;
96 int usetrailers, off, len = m->m_pkthdr.len;
97#define ac ((struct arpcom *)ifp)
98
99 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
100 error = ENETDOWN;
101 goto bad;
102 }
103 ifp->if_lastchange = time;
104 switch (dst->sa_family) {
105
106#ifdef INET
107 case AF_INET:
108 idst = ((struct sockaddr_in *)dst)->sin_addr;
109 if (!arpresolve(ac, m, &idst, edst, &usetrailers))
110 return (0); /* if not yet resolved */
111 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
112 mcopy = m_copy(m, 0, (int)M_COPYALL);
113 off = m->m_pkthdr.len - m->m_len;
114 if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
115 (m->m_flags & M_EXT) == 0 &&
116 m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
117 type = ETHERTYPE_TRAIL + (off>>9);
118 m->m_data -= 2 * sizeof (u_short);
119 m->m_len += 2 * sizeof (u_short);
120 len += 2 * sizeof (u_short);
121 *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
122 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
123 goto gottrailertype;
124 }
125 type = ETHERTYPE_IP;
126 goto gottype;
127#endif
128#ifdef NS
129 case AF_NS:
130 type = ETHERTYPE_NS;
131 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
132 (caddr_t)edst, sizeof (edst));
133 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
134 return (looutput(ifp, m, dst, rt));
135 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
136 mcopy = m_copy(m, 0, (int)M_COPYALL);
137 goto gottype;
138#endif
139#ifdef ISO
140 case AF_ISO: {
141 int snpalen;
142 struct llc *l;
143
144 iso_again:
145 if (rt && rt->rt_gateway && (rt->rt_flags & RTF_UP)) {
146 if (rt->rt_flags & RTF_GATEWAY) {
147 if (rt->rt_llinfo) {
148 rt = (struct rtentry *)rt->rt_llinfo;
149 goto iso_again;
150 }
151 } else {
152 register struct sockaddr_dl *sdl =
153 (struct sockaddr_dl *)rt->rt_gateway;
154 if (sdl && sdl->sdl_family == AF_LINK
155 && sdl->sdl_alen > 0) {
156 bcopy(LLADDR(sdl), (char *)edst,
157 sizeof(edst));
158 goto iso_resolved;
159 }
160 }
161 }
162 if ((error = iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
163 (char *)edst, &snpalen)) > 0)
164 goto bad; /* Not Resolved */
165 iso_resolved:
166 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
167 (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
168 M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
169 if (mcopy) {
170 eh = mtod(mcopy, struct ether_header *);
171 bcopy((caddr_t)edst,
172 (caddr_t)eh->ether_dhost, sizeof (edst));
173 bcopy((caddr_t)ac->ac_enaddr,
174 (caddr_t)eh->ether_shost, sizeof (edst));
175 }
176 }
177 M_PREPEND(m, 3, M_DONTWAIT);
178 if (m == NULL)
179 return (0);
180 type = m->m_pkthdr.len;
181 l = mtod(m, struct llc *);
182 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
183 l->llc_control = LLC_UI;
184 len += 3;
185 IFDEBUG(D_ETHER)
186 int i;
187 printf("unoutput: sending pkt to: ");
188 for (i=0; i<6; i++)
189 printf("%x ", edst[i] & 0xff);
190 printf("\n");
191 ENDDEBUG
192 } goto gottype;
193#endif ISO
194#ifdef RMP
195 case AF_RMP:
196 /*
197 * This is IEEE 802.3 -- the Ethernet `type' field is
198 * really a `length' field.
199 */
200 type = m->m_len;
201 bcopy((caddr_t)dst->sa_data, (caddr_t)edst, sizeof(edst));
202 break;
203#endif
204
205 case AF_UNSPEC:
206 eh = (struct ether_header *)dst->sa_data;
207 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
208 type = eh->ether_type;
209 goto gottype;
210
211 default:
212 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
213 dst->sa_family);
214 error = EAFNOSUPPORT;
215 goto bad;
216 }
217
218gottrailertype:
219 /*
220 * Packet to be sent as trailer: move first packet
221 * (control information) to end of chain.
222 */
223 while (m->m_next)
224 m = m->m_next;
225 m->m_next = m0;
226 m = m0->m_next;
227 m0->m_next = 0;
228
229gottype:
230 if (mcopy)
231 (void) looutput(ifp, mcopy, dst, rt);
232 /*
233 * Add local net header. If no space in first mbuf,
234 * allocate another.
235 */
236 M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
237 if (m == 0) {
238 error = ENOBUFS;
239 goto bad;
240 }
241 eh = mtod(m, struct ether_header *);
242 type = htons((u_short)type);
243 bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
244 sizeof(eh->ether_type));
245 bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
246 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
247 sizeof(eh->ether_shost));
248 s = splimp();
249 /*
250 * Queue message on interface, and start output if interface
251 * not yet active.
252 */
253 if (IF_QFULL(&ifp->if_snd)) {
254 IF_DROP(&ifp->if_snd);
255 splx(s);
256 error = ENOBUFS;
257 goto bad;
258 }
259 IF_ENQUEUE(&ifp->if_snd, m);
260 if ((ifp->if_flags & IFF_OACTIVE) == 0)
261 (*ifp->if_start)(ifp);
262 splx(s);
263 ifp->if_obytes += len + sizeof (struct ether_header);
264 if (edst[0] & 1)
265 ifp->if_omcasts++;
266 return (error);
267
268bad:
269 if (m)
270 m_freem(m);
271 return (error);
272}
273
274/*
275 * Process a received Ethernet packet;
276 * the packet is in the mbuf chain m without
277 * the ether header, which is provided separately.
278 */
279ether_input(ifp, eh, m)
280 struct ifnet *ifp;
281 register struct ether_header *eh;
282 struct mbuf *m;
283{
284 register struct ifqueue *inq;
285 register struct llc *l;
286 int s;
287
288 ifp->if_lastchange = time;
289 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
290 if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
291 sizeof(etherbroadcastaddr)) == 0)
292 m->m_flags |= M_BCAST;
293 else if (eh->ether_dhost[0] & 1)
294 m->m_flags |= M_MCAST;
295 if (m->m_flags & (M_BCAST|M_MCAST))
296 ifp->if_imcasts++;
297
298 switch (eh->ether_type) {
299#ifdef INET
300 case ETHERTYPE_IP:
301 schednetisr(NETISR_IP);
302 inq = &ipintrq;
303 break;
304
305 case ETHERTYPE_ARP:
306 arpinput((struct arpcom *)ifp, m);
307 return;
308#endif
309#ifdef NS
310 case ETHERTYPE_NS:
311 schednetisr(NETISR_NS);
312 inq = &nsintrq;
313 break;
314
315#endif
316 default:
317#ifdef ISO
318 if (eh->ether_type > ETHERMTU)
319 goto dropanyway;
320 l = mtod(m, struct llc *);
321 switch (l->llc_control) {
322 case LLC_UI:
323 /* LLC_UI_P forbidden in class 1 service */
324 if ((l->llc_dsap == LLC_ISO_LSAP) &&
325 (l->llc_ssap == LLC_ISO_LSAP)) {
326 /* LSAP for ISO */
327 if (m->m_pkthdr.len > eh->ether_type)
328 m_adj(m, eh->ether_type - m->m_pkthdr.len);
329 m->m_data += 3; /* XXX */
330 m->m_len -= 3; /* XXX */
331 m->m_pkthdr.len -= 3; /* XXX */
332 M_PREPEND(m, sizeof *eh, M_DONTWAIT);
333 if (m == 0)
334 return;
335 *mtod(m, struct ether_header *) = *eh;
336 IFDEBUG(D_ETHER)
337 printf("clnp packet");
338 ENDDEBUG
339 schednetisr(NETISR_ISO);
340 inq = &clnlintrq;
341 break;
342 }
343 goto dropanyway;
344
345 case LLC_XID:
346 case LLC_XID_P:
347 if(m->m_len < 6)
348 goto dropanyway;
349 l->llc_window = 0;
350 l->llc_fid = 9;
351 l->llc_class = 1;
352 l->llc_dsap = l->llc_ssap = 0;
353 /* Fall through to */
354 case LLC_TEST:
355 case LLC_TEST_P:
356 {
357 struct sockaddr sa;
358 register struct ether_header *eh2;
359 int i;
360 u_char c = l->llc_dsap;
361 l->llc_dsap = l->llc_ssap;
362 l->llc_ssap = c;
363 if (m->m_flags & (M_BCAST | M_MCAST))
364 bcopy((caddr_t)ac->ac_enaddr,
365 (caddr_t)eh->ether_dhost, 6);
366 sa.sa_family = AF_UNSPEC;
367 sa.sa_len = sizeof(sa);
368 eh2 = (struct ether_header *)sa.sa_data;
369 for (i = 0; i < 6; i++) {
370 eh2->ether_shost[i] = c = eh->ether_dhost[i];
371 eh2->ether_dhost[i] =
372 eh->ether_dhost[i] = eh->ether_shost[i];
373 eh->ether_shost[i] = c;
374 }
375 ifp->if_output(ifp, m, &sa);
376 return;
377 }
378 dropanyway:
379 default:
380 m_freem(m);
381 return;
382 }
383#else
384 m_freem(m);
385 return;
386#endif ISO
387 }
388
389 s = splimp();
390 if (IF_QFULL(inq)) {
391 IF_DROP(inq);
392 m_freem(m);
393 } else
394 IF_ENQUEUE(inq, m);
395 splx(s);
396}
397
398/*
399 * Convert Ethernet address to printable (loggable) representation.
400 */
401static char digits[] = "0123456789abcdef";
402char *
403ether_sprintf(ap)
404 register u_char *ap;
405{
406 register i;
407 static char etherbuf[18];
408 register char *cp = etherbuf;
409
410 for (i = 0; i < 6; i++) {
411 *cp++ = digits[*ap >> 4];
412 *cp++ = digits[*ap++ & 0xf];
413 *cp++ = ':';
414 }
415 *--cp = 0;
416 return (etherbuf);
417}