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 *
70c5ff60 33 * from: @(#)if_ethersubr.c 7.13 (Berkeley) 4/20/91
4c45483e 34 * $Id: if_ethersubr.c,v 1.3 1993/10/16 17:43:16 rgrimes Exp $
15637ed4
RG
35 */
36
37#include "param.h"
38#include "systm.h"
39#include "kernel.h"
40#include "malloc.h"
41#include "mbuf.h"
42#include "protosw.h"
43#include "socket.h"
44#include "ioctl.h"
45#include "errno.h"
46#include "syslog.h"
47
48#include "if.h"
49#include "netisr.h"
50#include "route.h"
51#include "if_llc.h"
52#include "if_dl.h"
53
54#include "machine/mtpr.h"
55
56#ifdef INET
57#include "../netinet/in.h"
58#include "../netinet/in_var.h"
59#endif
60#include "../netinet/if_ether.h"
61
62#ifdef NS
63#include "../netns/ns.h"
64#include "../netns/ns_if.h"
65#endif
66
67#ifdef ISO
68#include "../netiso/argo_debug.h"
69#include "../netiso/iso.h"
70#include "../netiso/iso_var.h"
71#include "../netiso/iso_snpac.h"
72#endif
73
74u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
75extern struct ifnet loif;
76
77/*
78 * Ethernet output routine.
79 * Encapsulate a packet of type family for the local net.
80 * Use trailer local net encapsulation if enough data in first
81 * packet leaves a multiple of 512 bytes of data in remainder.
82 * Assumes that ifp is actually pointer to arpcom structure.
83 */
4c45483e 84int
15637ed4
RG
85ether_output(ifp, m0, dst, rt)
86 register struct ifnet *ifp;
87 struct mbuf *m0;
88 struct sockaddr *dst;
89 struct rtentry *rt;
90{
91 short type;
92 int s, error = 0;
93 u_char edst[6];
94 struct in_addr idst;
95 register struct mbuf *m = m0;
96 struct mbuf *mcopy = (struct mbuf *)0;
97 register struct ether_header *eh;
98 int usetrailers, off, len = m->m_pkthdr.len;
99#define ac ((struct arpcom *)ifp)
100
101 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
102 error = ENETDOWN;
103 goto bad;
104 }
105 ifp->if_lastchange = time;
106 switch (dst->sa_family) {
107
108#ifdef INET
109 case AF_INET:
110 idst = ((struct sockaddr_in *)dst)->sin_addr;
111 if (!arpresolve(ac, m, &idst, edst, &usetrailers))
112 return (0); /* if not yet resolved */
113 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
114 mcopy = m_copy(m, 0, (int)M_COPYALL);
115 off = m->m_pkthdr.len - m->m_len;
116 if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
117 (m->m_flags & M_EXT) == 0 &&
118 m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
119 type = ETHERTYPE_TRAIL + (off>>9);
120 m->m_data -= 2 * sizeof (u_short);
121 m->m_len += 2 * sizeof (u_short);
122 len += 2 * sizeof (u_short);
123 *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
124 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
125 goto gottrailertype;
126 }
127 type = ETHERTYPE_IP;
128 goto gottype;
129#endif
130#ifdef NS
131 case AF_NS:
132 type = ETHERTYPE_NS;
133 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
134 (caddr_t)edst, sizeof (edst));
135 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
136 return (looutput(ifp, m, dst, rt));
137 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
138 mcopy = m_copy(m, 0, (int)M_COPYALL);
139 goto gottype;
140#endif
141#ifdef ISO
142 case AF_ISO: {
143 int snpalen;
144 struct llc *l;
145
146 iso_again:
147 if (rt && rt->rt_gateway && (rt->rt_flags & RTF_UP)) {
148 if (rt->rt_flags & RTF_GATEWAY) {
149 if (rt->rt_llinfo) {
150 rt = (struct rtentry *)rt->rt_llinfo;
151 goto iso_again;
152 }
153 } else {
154 register struct sockaddr_dl *sdl =
155 (struct sockaddr_dl *)rt->rt_gateway;
156 if (sdl && sdl->sdl_family == AF_LINK
157 && sdl->sdl_alen > 0) {
158 bcopy(LLADDR(sdl), (char *)edst,
159 sizeof(edst));
160 goto iso_resolved;
161 }
162 }
163 }
164 if ((error = iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
165 (char *)edst, &snpalen)) > 0)
166 goto bad; /* Not Resolved */
167 iso_resolved:
168 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
169 (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
170 M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
171 if (mcopy) {
172 eh = mtod(mcopy, struct ether_header *);
173 bcopy((caddr_t)edst,
174 (caddr_t)eh->ether_dhost, sizeof (edst));
175 bcopy((caddr_t)ac->ac_enaddr,
176 (caddr_t)eh->ether_shost, sizeof (edst));
177 }
178 }
179 M_PREPEND(m, 3, M_DONTWAIT);
180 if (m == NULL)
181 return (0);
182 type = m->m_pkthdr.len;
183 l = mtod(m, struct llc *);
184 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
185 l->llc_control = LLC_UI;
186 len += 3;
187 IFDEBUG(D_ETHER)
188 int i;
189 printf("unoutput: sending pkt to: ");
190 for (i=0; i<6; i++)
191 printf("%x ", edst[i] & 0xff);
192 printf("\n");
193 ENDDEBUG
194 } goto gottype;
195#endif ISO
196#ifdef RMP
197 case AF_RMP:
198 /*
199 * This is IEEE 802.3 -- the Ethernet `type' field is
200 * really a `length' field.
201 */
202 type = m->m_len;
203 bcopy((caddr_t)dst->sa_data, (caddr_t)edst, sizeof(edst));
204 break;
205#endif
206
207 case AF_UNSPEC:
208 eh = (struct ether_header *)dst->sa_data;
209 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
210 type = eh->ether_type;
211 goto gottype;
212
213 default:
214 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
215 dst->sa_family);
216 error = EAFNOSUPPORT;
217 goto bad;
218 }
219
220gottrailertype:
221 /*
222 * Packet to be sent as trailer: move first packet
223 * (control information) to end of chain.
224 */
225 while (m->m_next)
226 m = m->m_next;
227 m->m_next = m0;
228 m = m0->m_next;
229 m0->m_next = 0;
230
231gottype:
232 if (mcopy)
233 (void) looutput(ifp, mcopy, dst, rt);
234 /*
235 * Add local net header. If no space in first mbuf,
236 * allocate another.
237 */
238 M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
239 if (m == 0) {
240 error = ENOBUFS;
241 goto bad;
242 }
243 eh = mtod(m, struct ether_header *);
47110967
RG
244
245 eh->ether_type = htons((u_short) type);
246
247 *(int *) eh->ether_dhost = *(int *) edst;
248 ((short *) eh->ether_dhost)[2] = ((short *) edst)[2];
249
250 *(int *) eh->ether_shost = *(int *) ac->ac_enaddr;
251 ((short *) eh->ether_shost)[2] = ((short *) ac->ac_enaddr)[2];
252
15637ed4
RG
253 s = splimp();
254 /*
255 * Queue message on interface, and start output if interface
256 * not yet active.
257 */
258 if (IF_QFULL(&ifp->if_snd)) {
259 IF_DROP(&ifp->if_snd);
260 splx(s);
261 error = ENOBUFS;
262 goto bad;
263 }
264 IF_ENQUEUE(&ifp->if_snd, m);
265 if ((ifp->if_flags & IFF_OACTIVE) == 0)
266 (*ifp->if_start)(ifp);
267 splx(s);
268 ifp->if_obytes += len + sizeof (struct ether_header);
269 if (edst[0] & 1)
270 ifp->if_omcasts++;
271 return (error);
272
273bad:
274 if (m)
275 m_freem(m);
276 return (error);
277}
278
279/*
280 * Process a received Ethernet packet;
281 * the packet is in the mbuf chain m without
282 * the ether header, which is provided separately.
283 */
4c45483e 284void
15637ed4
RG
285ether_input(ifp, eh, m)
286 struct ifnet *ifp;
287 register struct ether_header *eh;
288 struct mbuf *m;
289{
290 register struct ifqueue *inq;
291 register struct llc *l;
292 int s;
293
294 ifp->if_lastchange = time;
295 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
296 if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
297 sizeof(etherbroadcastaddr)) == 0)
298 m->m_flags |= M_BCAST;
299 else if (eh->ether_dhost[0] & 1)
300 m->m_flags |= M_MCAST;
301 if (m->m_flags & (M_BCAST|M_MCAST))
302 ifp->if_imcasts++;
303
304 switch (eh->ether_type) {
305#ifdef INET
306 case ETHERTYPE_IP:
307 schednetisr(NETISR_IP);
308 inq = &ipintrq;
309 break;
310
311 case ETHERTYPE_ARP:
312 arpinput((struct arpcom *)ifp, m);
313 return;
314#endif
315#ifdef NS
316 case ETHERTYPE_NS:
317 schednetisr(NETISR_NS);
318 inq = &nsintrq;
319 break;
320
321#endif
322 default:
323#ifdef ISO
324 if (eh->ether_type > ETHERMTU)
325 goto dropanyway;
326 l = mtod(m, struct llc *);
327 switch (l->llc_control) {
328 case LLC_UI:
329 /* LLC_UI_P forbidden in class 1 service */
330 if ((l->llc_dsap == LLC_ISO_LSAP) &&
331 (l->llc_ssap == LLC_ISO_LSAP)) {
332 /* LSAP for ISO */
333 if (m->m_pkthdr.len > eh->ether_type)
334 m_adj(m, eh->ether_type - m->m_pkthdr.len);
335 m->m_data += 3; /* XXX */
336 m->m_len -= 3; /* XXX */
337 m->m_pkthdr.len -= 3; /* XXX */
338 M_PREPEND(m, sizeof *eh, M_DONTWAIT);
339 if (m == 0)
340 return;
341 *mtod(m, struct ether_header *) = *eh;
342 IFDEBUG(D_ETHER)
343 printf("clnp packet");
344 ENDDEBUG
345 schednetisr(NETISR_ISO);
346 inq = &clnlintrq;
347 break;
348 }
349 goto dropanyway;
350
351 case LLC_XID:
352 case LLC_XID_P:
353 if(m->m_len < 6)
354 goto dropanyway;
355 l->llc_window = 0;
356 l->llc_fid = 9;
357 l->llc_class = 1;
358 l->llc_dsap = l->llc_ssap = 0;
359 /* Fall through to */
360 case LLC_TEST:
361 case LLC_TEST_P:
362 {
363 struct sockaddr sa;
364 register struct ether_header *eh2;
365 int i;
366 u_char c = l->llc_dsap;
367 l->llc_dsap = l->llc_ssap;
368 l->llc_ssap = c;
369 if (m->m_flags & (M_BCAST | M_MCAST))
370 bcopy((caddr_t)ac->ac_enaddr,
371 (caddr_t)eh->ether_dhost, 6);
372 sa.sa_family = AF_UNSPEC;
373 sa.sa_len = sizeof(sa);
374 eh2 = (struct ether_header *)sa.sa_data;
375 for (i = 0; i < 6; i++) {
376 eh2->ether_shost[i] = c = eh->ether_dhost[i];
377 eh2->ether_dhost[i] =
378 eh->ether_dhost[i] = eh->ether_shost[i];
379 eh->ether_shost[i] = c;
380 }
4c45483e 381 ifp->if_output(ifp, m, &sa, (struct rtentry *)0);
15637ed4
RG
382 return;
383 }
384 dropanyway:
385 default:
386 m_freem(m);
387 return;
388 }
389#else
390 m_freem(m);
391 return;
4c45483e 392#endif /* ISO */
15637ed4
RG
393 }
394
395 s = splimp();
396 if (IF_QFULL(inq)) {
397 IF_DROP(inq);
398 m_freem(m);
399 } else
400 IF_ENQUEUE(inq, m);
401 splx(s);
402}
403
404/*
405 * Convert Ethernet address to printable (loggable) representation.
406 */
407static char digits[] = "0123456789abcdef";
408char *
409ether_sprintf(ap)
410 register u_char *ap;
411{
412 register i;
413 static char etherbuf[18];
414 register char *cp = etherbuf;
415
416 for (i = 0; i < 6; i++) {
417 *cp++ = digits[*ap >> 4];
418 *cp++ = digits[*ap++ & 0xf];
419 *cp++ = ':';
420 }
421 *--cp = 0;
422 return (etherbuf);
423}