start routines can't reliably return errors;fix bug in ISO processing;
[unix-history] / usr / src / sys / net / if_ethersubr.c
CommitLineData
132c65ba
KF
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 *
ae4c8bc9 17 * @(#)if_ethersubr.c 7.4 (Berkeley) %G%
132c65ba
KF
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"
38a81509 33#include "if_llc.h"
132c65ba 34
d301d150 35#include "machine/mtpr.h"
132c65ba
KF
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
b72a6efb
KS
48#ifdef ISO
49#include "../netiso/argo_debug.h"
50#include "../netiso/iso.h"
51#include "../netiso/iso_var.h"
52#endif
53
132c65ba 54u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
38a81509 55extern struct ifnet loif;
132c65ba
KF
56
57/*
58 * Ethernet output routine.
59 * Encapsulate a packet of type family for the local net.
60 * Use trailer local net encapsulation if enough data in first
61 * packet leaves a multiple of 512 bytes of data in remainder.
62 * Assumes that ifp is actually pointer to arpcom structure.
63 */
b72a6efb 64ether_output(ifp, m0, dst)
132c65ba
KF
65 register struct ifnet *ifp;
66 struct mbuf *m0;
67 struct sockaddr *dst;
68{
38a81509
MK
69 short type;
70 int s, error = 0;
132c65ba
KF
71 u_char edst[6];
72 struct in_addr idst;
73 register struct mbuf *m = m0;
38a81509 74 struct mbuf *mcopy = (struct mbuf *)0;
132c65ba 75 register struct ether_header *eh;
38a81509 76 int usetrailers, off;
132c65ba
KF
77#define ac ((struct arpcom *)ifp)
78
79 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
80 error = ENETDOWN;
81 goto bad;
82 }
b72a6efb
KS
83 if (ifp->if_flags & IFF_SIMPLEX && dst->sa_family != AF_UNSPEC &&
84 !bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, sizeof (edst)))
85 mcopy = m_copy(m, 0, (int)M_COPYALL);
132c65ba
KF
86 switch (dst->sa_family) {
87
88#ifdef INET
89 case AF_INET:
90 idst = ((struct sockaddr_in *)dst)->sin_addr;
91 if (!arpresolve(ac, m, &idst, edst, &usetrailers))
92 return (0); /* if not yet resolved */
b72a6efb
KS
93 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
94 mcopy = m_copy(m, 0, (int)M_COPYALL);
132c65ba
KF
95 off = m->m_pkthdr.len - m->m_len;
96 if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
97 (m->m_flags & M_EXT) == 0 &&
98 m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
99 type = ETHERTYPE_TRAIL + (off>>9);
100 m->m_data -= 2 * sizeof (u_short);
101 m->m_len += 2 * sizeof (u_short);
102 *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
103 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
104 goto gottrailertype;
105 }
106 type = ETHERTYPE_IP;
132c65ba
KF
107 goto gottype;
108#endif
109#ifdef NS
110 case AF_NS:
111 type = ETHERTYPE_NS;
38a81509
MK
112 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
113 return(looutput(&loif, m, dst));
132c65ba 114 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
38a81509 115 (caddr_t)edst, sizeof (edst));
b72a6efb
KS
116 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
117 mcopy = m_copy(m, 0, (int)M_COPYALL);
132c65ba
KF
118 goto gottype;
119#endif
38a81509
MK
120#ifdef ISO
121 case AF_ISO: {
b72a6efb 122 int len;
38a81509 123 int ret;
b72a6efb
KS
124 struct llc *l;
125
126 if ((ret = iso_tryloopback(m, (struct sockaddr_iso *)dst)) >= 0)
127 return (ret);
128 ret = iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
129 (char *)edst, &len);
130 if (ret > 0) {
131 m_freem(m); /* Not Resolved */
132 return(ret);
38a81509
MK
133 }
134 M_PREPEND(m, 3, M_DONTWAIT);
b72a6efb 135 if (m == NULL)
38a81509 136 return(0);
38a81509
MK
137 type = m->m_pkthdr.len;
138 l = mtod(m, struct llc *);
139 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
140 l->llc_control = LLC_UI;
141 IFDEBUG(D_ETHER)
142 int i;
143 printf("unoutput: sending pkt to: ");
144 for (i=0; i<6; i++)
145 printf("%x ", edst[i] & 0xff);
146 printf("\n");
147 ENDDEBUG
148 } goto gottype;
149#endif ISO
132c65ba
KF
150 case AF_UNSPEC:
151 eh = (struct ether_header *)dst->sa_data;
152 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
153 type = eh->ether_type;
154 goto gottype;
155
156 default:
157 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
158 dst->sa_family);
159 error = EAFNOSUPPORT;
160 goto bad;
161 }
162
163gottrailertype:
164 /*
165 * Packet to be sent as trailer: move first packet
166 * (control information) to end of chain.
167 */
168 while (m->m_next)
169 m = m->m_next;
170 m->m_next = m0;
171 m = m0->m_next;
172 m0->m_next = 0;
132c65ba
KF
173
174gottype:
175 /*
176 * Add local net header. If no space in first mbuf,
177 * allocate another.
178 */
179 M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
180 if (m == 0) {
181 error = ENOBUFS;
182 goto bad;
183 }
184 eh = mtod(m, struct ether_header *);
38a81509
MK
185 type = htons((u_short)type);
186 bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
187 sizeof(eh->ether_type));
132c65ba
KF
188 bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
189 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
190 sizeof(eh->ether_shost));
132c65ba
KF
191 /*
192 * Queue message on interface, and start output if interface
193 * not yet active.
194 */
195 s = splimp();
196 if (IF_QFULL(&ifp->if_snd)) {
197 IF_DROP(&ifp->if_snd);
198 splx(s);
38a81509
MK
199 error = ENOBUFS;
200 goto bad;
132c65ba
KF
201 }
202 IF_ENQUEUE(&ifp->if_snd, m);
203 if ((ifp->if_flags & IFF_OACTIVE) == 0)
ae4c8bc9 204 (*ifp->if_start)(ifp);
132c65ba 205 splx(s);
38a81509
MK
206 if (mcopy)
207 (void) looutput(&loif, mcopy, dst);
208 return (error);
132c65ba
KF
209
210bad:
38a81509
MK
211 if (mcopy)
212 m_freem(mcopy);
213 if (m)
214 m_freem(m);
132c65ba
KF
215 return (error);
216}
217
218/*
ae4c8bc9
BJ
219 * Process a received Ethernet packet;
220 * the packet is in the mbuf chain m without
221 * the ether header, which is provided separately.
132c65ba 222 */
b72a6efb 223ether_input(ifp, eh, m)
132c65ba
KF
224 struct ifnet *ifp;
225 register struct ether_header *eh;
226 struct mbuf *m;
227{
228 register struct ifqueue *inq;
38a81509 229 register struct llc *l;
132c65ba
KF
230 int s;
231
38a81509 232 if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
132c65ba
KF
233 sizeof(etherbroadcastaddr)) == 0)
234 m->m_flags |= M_BCAST;
38a81509
MK
235 else if (eh->ether_dhost[0] & 1)
236 m->m_flags |= M_MCAST;
132c65ba
KF
237
238 switch (eh->ether_type) {
239#ifdef INET
240 case ETHERTYPE_IP:
241 schednetisr(NETISR_IP);
242 inq = &ipintrq;
243 break;
244
245 case ETHERTYPE_ARP:
246 arpinput((struct arpcom *)ifp, m);
247 return;
248#endif
249#ifdef NS
250 case ETHERTYPE_NS:
251 schednetisr(NETISR_NS);
252 inq = &nsintrq;
253 break;
254
255#endif
256 default:
ae4c8bc9 257#ifdef ISO
b72a6efb 258 if (eh->ether_type > ETHERMTU)
38a81509
MK
259 goto dropanyway;
260 l = mtod(m, struct llc *);
261 switch (l->llc_control) {
262 case LLC_UI:
263 /* LLC_UI_P forbidden in class 1 service */
264 if ((l->llc_dsap == LLC_ISO_LSAP) &&
265 (l->llc_ssap == LLC_ISO_LSAP)) {
38a81509 266 /* LSAP for ISO */
ae4c8bc9
BJ
267 m->m_data += 3; /* XXX */
268 m->m_len -= 3; /* XXX */
269 m->m_pkthdr.len -= 3; /* XXX */
b72a6efb
KS
270 M_PREPEND(m, sizeof *eh, M_DONTWAIT);
271 if (m == 0)
272 return;
273 *mtod(m, struct ether_header *) = *eh;
274 IFDEBUG(D_ETHER)
275 printf("clnp packet");
276 ENDDEBUG
277 schednetisr(NETISR_ISO);
38a81509 278 inq = &clnlintrq;
ae4c8bc9 279 break;
38a81509 280 }
ae4c8bc9
BJ
281 goto dropanyway;
282
38a81509
MK
283 case LLC_XID:
284 case LLC_XID_P:
285 if(m->m_len < 6)
286 goto dropanyway;
287 l->llc_window = 0;
288 l->llc_fid = 9;
289 l->llc_class = 1;
290 l->llc_dsap = l->llc_ssap = 0;
291 /* Fall through to */
292 case LLC_TEST:
293 case LLC_TEST_P:
294 {
295 struct sockaddr sa;
296 register struct ether_header *eh2;
297 int i;
298 u_char c = l->llc_dsap;
299 l->llc_dsap = l->llc_ssap;
300 l->llc_ssap = c;
b72a6efb
KS
301 if (m->m_flags & (M_BCAST | M_MCAST))
302 bcopy((caddr_t)ac->ac_enaddr,
303 (caddr_t)eh->ether_dhost, 6);
38a81509 304 sa.sa_family = AF_UNSPEC;
b72a6efb 305 sa.sa_len = sizeof(sa);
38a81509
MK
306 eh2 = (struct ether_header *)sa.sa_data;
307 for (i = 0; i < 6; i++) {
308 eh2->ether_shost[i] = c = eh->ether_dhost[i];
309 eh2->ether_dhost[i] =
310 eh->ether_dhost[i] = eh->ether_shost[i];
311 eh->ether_shost[i] = c;
312 }
313 ifp->if_output(ifp, m, &sa);
314 return;
315 }
316 dropanyway:
317 default:
318 m_freem(m);
319 return;
320 }
ae4c8bc9
BJ
321#else
322 m_freem(m);
323 return;
324#endif ISO
132c65ba
KF
325 }
326
327 s = splimp();
328 if (IF_QFULL(inq)) {
329 IF_DROP(inq);
330 m_freem(m);
331 } else
332 IF_ENQUEUE(inq, m);
333 splx(s);
334}
335
336/*
337 * Convert Ethernet address to printable (loggable) representation.
338 */
b72a6efb 339static char digits[] = "0123456789abcdef";
132c65ba
KF
340char *
341ether_sprintf(ap)
342 register u_char *ap;
343{
344 register i;
345 static char etherbuf[18];
346 register char *cp = etherbuf;
132c65ba
KF
347
348 for (i = 0; i < 6; i++) {
349 *cp++ = digits[*ap >> 4];
350 *cp++ = digits[*ap++ & 0xf];
351 *cp++ = ':';
352 }
353 *--cp = 0;
354 return (etherbuf);
355}