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