FreeBSD/Linux Kernel Cross Reference
sys/net/if_ef.c
1 /*-
2 * Copyright (c) 1999, 2000 Boris Popov
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 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29 #include "opt_inet.h"
30 #include "opt_ipx.h"
31 #include "opt_ef.h"
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/sockio.h>
36 #include <sys/malloc.h>
37 #include <sys/mbuf.h>
38 #include <sys/socket.h>
39 #include <sys/syslog.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42
43 #include <net/ethernet.h>
44 #include <net/if_llc.h>
45 #include <net/if.h>
46 #include <net/if_arp.h>
47 #include <net/if_dl.h>
48 #include <net/if_types.h>
49 #include <net/netisr.h>
50 #include <net/route.h>
51 #include <net/bpf.h>
52
53 #ifdef INET
54 #include <netinet/in.h>
55 #include <netinet/in_var.h>
56 #include <netinet/if_ether.h>
57 #endif
58
59 #ifdef IPX
60 #include <netipx/ipx.h>
61 #include <netipx/ipx_if.h>
62 #endif
63
64 /* If none of the supported layers is enabled explicitly enable them all */
65 #if !defined(ETHER_II) && !defined(ETHER_8023) && !defined(ETHER_8022) && \
66 !defined(ETHER_SNAP)
67 #define ETHER_II 1
68 #define ETHER_8023 1
69 #define ETHER_8022 1
70 #define ETHER_SNAP 1
71 #endif
72
73 /* internal frame types */
74 #define ETHER_FT_EII 0 /* Ethernet_II - default */
75 #define ETHER_FT_8023 1 /* 802.3 (Novell) */
76 #define ETHER_FT_8022 2 /* 802.2 */
77 #define ETHER_FT_SNAP 3 /* SNAP */
78 #define EF_NFT 4 /* total number of frame types */
79
80 #ifdef EF_DEBUG
81 #define EFDEBUG(format, args...) printf("%s: "format, __func__ ,## args)
82 #else
83 #define EFDEBUG(format, args...)
84 #endif
85
86 #define EFERROR(format, args...) printf("%s: "format, __func__ ,## args)
87
88 struct efnet {
89 struct arpcom ef_ac;
90 struct ifnet * ef_ifp;
91 int ef_frametype;
92 };
93
94 struct ef_link {
95 SLIST_ENTRY(ef_link) el_next;
96 struct ifnet *el_ifp; /* raw device for this clones */
97 struct efnet *el_units[EF_NFT]; /* our clones */
98 };
99
100 static SLIST_HEAD(ef_link_head, ef_link) efdev = {NULL};
101 static int efcount;
102
103 extern int (*ef_inputp)(struct ifnet*, struct ether_header *eh, struct mbuf *m);
104 extern int (*ef_outputp)(struct ifnet *ifp, struct mbuf **mp,
105 struct sockaddr *dst, short *tp, int *hlen);
106
107 /*
108 static void ef_reset (struct ifnet *);
109 */
110 static int ef_attach(struct efnet *sc);
111 static int ef_detach(struct efnet *sc);
112 static void ef_init(void *);
113 static int ef_ioctl(struct ifnet *, u_long, caddr_t);
114 static void ef_start(struct ifnet *);
115 static int ef_input(struct ifnet*, struct ether_header *, struct mbuf *);
116 static int ef_output(struct ifnet *ifp, struct mbuf **mp,
117 struct sockaddr *dst, short *tp, int *hlen);
118
119 static int ef_load(void);
120 static int ef_unload(void);
121
122 /*
123 * Install the interface, most of structure initialization done in ef_clone()
124 */
125 static int
126 ef_attach(struct efnet *sc)
127 {
128 struct ifnet *ifp = (struct ifnet*)&sc->ef_ac.ac_if;
129 struct ifaddr *ifa2;
130 struct sockaddr_dl *sdl2;
131
132 ifp->if_start = ef_start;
133 ifp->if_watchdog = NULL;
134 ifp->if_init = ef_init;
135 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
136 ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
137 /*
138 * Attach the interface
139 */
140 ifa2 = ifaddr_byindex(sc->ef_ifp->if_index);
141 sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
142 ether_ifattach(ifp, LLADDR(sdl2));
143
144 ifp->if_resolvemulti = 0;
145 ifp->if_type = IFT_XETHER;
146 ifp->if_flags |= IFF_RUNNING;
147
148 bcopy(LLADDR(sdl2), sc->ef_ac.ac_enaddr, ETHER_ADDR_LEN);
149
150 EFDEBUG("%s: attached\n", ifp->if_xname);
151 return 1;
152 }
153
154 /*
155 * This is for _testing_only_, just removes interface from interfaces list
156 */
157 static int
158 ef_detach(struct efnet *sc)
159 {
160 struct ifnet *ifp = (struct ifnet*)&sc->ef_ac.ac_if;
161 int s;
162
163 s = splimp();
164
165 if (ifp->if_flags & IFF_UP) {
166 if_down(ifp);
167 if (ifp->if_flags & IFF_RUNNING) {
168 /* find internet addresses and delete routes */
169 register struct ifaddr *ifa;
170 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
171 rtinit(ifa, (int)RTM_DELETE, 0);
172 }
173 }
174 }
175 IFNET_WLOCK();
176 TAILQ_REMOVE(&ifnet, ifp, if_link);
177 IFNET_WUNLOCK();
178 splx(s);
179 return 0;
180 }
181
182 static void
183 ef_init(void *foo) {
184 return;
185 }
186
187 static int
188 ef_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
189 {
190 struct efnet *sc = ifp->if_softc;
191 struct ifaddr *ifa = (struct ifaddr*)data;
192 int s, error;
193
194 EFDEBUG("IOCTL %ld for %s\n", cmd, ifp->if_xname);
195 error = 0;
196 s = splimp();
197 switch (cmd) {
198 case SIOCSIFFLAGS:
199 error = 0;
200 break;
201 case SIOCSIFADDR:
202 if (sc->ef_frametype == ETHER_FT_8023 &&
203 ifa->ifa_addr->sa_family != AF_IPX) {
204 error = EAFNOSUPPORT;
205 break;
206 }
207 ifp->if_flags |= IFF_UP;
208 /* FALL THROUGH */
209 default:
210 error = ether_ioctl(ifp, cmd, data);
211 break;
212 }
213 splx(s);
214 return error;
215 }
216
217 /*
218 * Currently packet prepared in the ether_output(), but this can be a better
219 * place.
220 */
221 static void
222 ef_start(struct ifnet *ifp)
223 {
224 struct efnet *sc = (struct efnet*)ifp->if_softc;
225 struct ifnet *p;
226 struct mbuf *m;
227 int error;
228
229 ifp->if_flags |= IFF_OACTIVE;
230 p = sc->ef_ifp;
231
232 EFDEBUG("\n");
233 for (;;) {
234 IF_DEQUEUE(&ifp->if_snd, m);
235 if (m == 0)
236 break;
237 BPF_MTAP(ifp, m);
238 IFQ_HANDOFF(p, m, error);
239 if (error) {
240 ifp->if_oerrors++;
241 continue;
242 }
243 ifp->if_opackets++;
244 }
245 ifp->if_flags &= ~IFF_OACTIVE;
246 return;
247 }
248
249 /*
250 * Inline functions do not put additional overhead to procedure call or
251 * parameter passing but simplify the code
252 */
253 static int __inline
254 ef_inputEII(struct mbuf *m, struct ether_header *eh, u_short ether_type)
255 {
256 int isr;
257
258 switch(ether_type) {
259 #ifdef IPX
260 case ETHERTYPE_IPX:
261 isr = NETISR_IPX;
262 break;
263 #endif
264 #ifdef INET
265 case ETHERTYPE_IP:
266 if (ip_fastforward(m))
267 return (0);
268 isr = NETISR_IP;
269 break;
270
271 case ETHERTYPE_ARP:
272 isr = NETISR_ARP;
273 break;
274 #endif
275 default:
276 return (EPROTONOSUPPORT);
277 }
278 netisr_dispatch(isr, m);
279 return (0);
280 }
281
282 static int __inline
283 ef_inputSNAP(struct mbuf *m, struct ether_header *eh, struct llc* l,
284 u_short ether_type)
285 {
286 int isr;
287
288 switch(ether_type) {
289 #ifdef IPX
290 case ETHERTYPE_IPX:
291 m_adj(m, 8);
292 isr = NETISR_IPX;
293 break;
294 #endif
295 default:
296 return (EPROTONOSUPPORT);
297 }
298 netisr_dispatch(isr, m);
299 return (0);
300 }
301
302 static int __inline
303 ef_input8022(struct mbuf *m, struct ether_header *eh, struct llc* l,
304 u_short ether_type)
305 {
306 int isr;
307
308 switch(ether_type) {
309 #ifdef IPX
310 case 0xe0:
311 m_adj(m, 3);
312 isr = NETISR_IPX;
313 break;
314 #endif
315 default:
316 return (EPROTONOSUPPORT);
317 }
318 netisr_dispatch(isr, m);
319 return (0);
320 }
321
322 /*
323 * Called from ether_input()
324 */
325 static int
326 ef_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m)
327 {
328 u_short ether_type;
329 int ft = -1;
330 struct efnet *efp;
331 struct ifnet *eifp;
332 struct llc *l;
333 struct ef_link *efl;
334 int isr;
335
336 ether_type = ntohs(eh->ether_type);
337 l = NULL;
338 if (ether_type < ETHERMTU) {
339 l = mtod(m, struct llc*);
340 if (l->llc_dsap == 0xff && l->llc_ssap == 0xff) {
341 /*
342 * Novell's "802.3" frame
343 */
344 ft = ETHER_FT_8023;
345 } else if (l->llc_dsap == 0xaa && l->llc_ssap == 0xaa) {
346 /*
347 * 802.2/SNAP
348 */
349 ft = ETHER_FT_SNAP;
350 ether_type = ntohs(l->llc_un.type_snap.ether_type);
351 } else if (l->llc_dsap == l->llc_ssap) {
352 /*
353 * 802.3/802.2
354 */
355 ft = ETHER_FT_8022;
356 ether_type = l->llc_ssap;
357 }
358 } else
359 ft = ETHER_FT_EII;
360
361 if (ft == -1) {
362 EFDEBUG("Unrecognised ether_type %x\n", ether_type);
363 return EPROTONOSUPPORT;
364 }
365
366 /*
367 * Check if interface configured for the given frame
368 */
369 efp = NULL;
370 SLIST_FOREACH(efl, &efdev, el_next) {
371 if (efl->el_ifp == ifp) {
372 efp = efl->el_units[ft];
373 break;
374 }
375 }
376 if (efp == NULL) {
377 EFDEBUG("Can't find if for %d\n", ft);
378 return EPROTONOSUPPORT;
379 }
380 eifp = &efp->ef_ac.ac_if;
381 if ((eifp->if_flags & IFF_UP) == 0)
382 return EPROTONOSUPPORT;
383 eifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
384 m->m_pkthdr.rcvif = eifp;
385
386 BPF_MTAP2(eifp, eh, ETHER_HDR_LEN, m);
387 /*
388 * Now we ready to adjust mbufs and pass them to protocol intr's
389 */
390 switch(ft) {
391 case ETHER_FT_EII:
392 return (ef_inputEII(m, eh, ether_type));
393 #ifdef IPX
394 case ETHER_FT_8023: /* only IPX can be here */
395 isr = NETISR_IPX;
396 break;
397 #endif
398 case ETHER_FT_SNAP:
399 return (ef_inputSNAP(m, eh, l, ether_type));
400 case ETHER_FT_8022:
401 return (ef_input8022(m, eh, l, ether_type));
402 default:
403 EFDEBUG("No support for frame %d and proto %04x\n",
404 ft, ether_type);
405 return (EPROTONOSUPPORT);
406 }
407 netisr_dispatch(isr, m);
408 return (0);
409 }
410
411 static int
412 ef_output(struct ifnet *ifp, struct mbuf **mp, struct sockaddr *dst, short *tp,
413 int *hlen)
414 {
415 struct efnet *sc = (struct efnet*)ifp->if_softc;
416 struct mbuf *m = *mp;
417 u_char *cp;
418 short type;
419
420 if (ifp->if_type != IFT_XETHER)
421 return ENETDOWN;
422 switch (sc->ef_frametype) {
423 case ETHER_FT_EII:
424 #ifdef IPX
425 type = htons(ETHERTYPE_IPX);
426 #else
427 return EPFNOSUPPORT;
428 #endif
429 break;
430 case ETHER_FT_8023:
431 type = htons(m->m_pkthdr.len);
432 break;
433 case ETHER_FT_8022:
434 M_PREPEND(m, ETHER_HDR_LEN + 3, M_TRYWAIT);
435 if (m == NULL) {
436 *mp = NULL;
437 return ENOBUFS;
438 }
439 /*
440 * Ensure that ethernet header and next three bytes
441 * will fit into single mbuf
442 */
443 m = m_pullup(m, ETHER_HDR_LEN + 3);
444 if (m == NULL) {
445 *mp = NULL;
446 return ENOBUFS;
447 }
448 m_adj(m, ETHER_HDR_LEN);
449 type = htons(m->m_pkthdr.len);
450 cp = mtod(m, u_char *);
451 *cp++ = 0xE0;
452 *cp++ = 0xE0;
453 *cp++ = 0x03;
454 *hlen += 3;
455 break;
456 case ETHER_FT_SNAP:
457 M_PREPEND(m, 8, M_TRYWAIT);
458 if (m == NULL) {
459 *mp = NULL;
460 return ENOBUFS;
461 }
462 type = htons(m->m_pkthdr.len);
463 cp = mtod(m, u_char *);
464 bcopy("\xAA\xAA\x03\x00\x00\x00\x81\x37", cp, 8);
465 *hlen += 8;
466 break;
467 default:
468 return EPFNOSUPPORT;
469 }
470 *mp = m;
471 *tp = type;
472 return 0;
473 }
474
475 /*
476 * Create clone from the given interface
477 */
478 static int
479 ef_clone(struct ef_link *efl, int ft)
480 {
481 struct efnet *efp;
482 struct ifnet *eifp;
483 struct ifnet *ifp = efl->el_ifp;
484
485 efp = (struct efnet*)malloc(sizeof(struct efnet), M_IFADDR,
486 M_WAITOK | M_ZERO);
487 if (efp == NULL)
488 return ENOMEM;
489 efp->ef_ifp = ifp;
490 efp->ef_frametype = ft;
491 eifp = &efp->ef_ac.ac_if;
492 snprintf(eifp->if_xname, IFNAMSIZ,
493 "%sf%d", ifp->if_xname, efp->ef_frametype);
494 eifp->if_dname = "ef";
495 eifp->if_dunit = IF_DUNIT_NONE;
496 eifp->if_softc = efp;
497 if (ifp->if_ioctl)
498 eifp->if_ioctl = ef_ioctl;
499 efl->el_units[ft] = efp;
500 return 0;
501 }
502
503 static int
504 ef_load(void)
505 {
506 struct ifnet *ifp;
507 struct efnet *efp;
508 struct ef_link *efl = NULL;
509 int error = 0, d;
510
511 IFNET_RLOCK();
512 TAILQ_FOREACH(ifp, &ifnet, if_link) {
513 if (ifp->if_type != IFT_ETHER) continue;
514 EFDEBUG("Found interface %s\n", ifp->if_xname);
515 efl = (struct ef_link*)malloc(sizeof(struct ef_link),
516 M_IFADDR, M_WAITOK | M_ZERO);
517 if (efl == NULL) {
518 error = ENOMEM;
519 break;
520 }
521
522 efl->el_ifp = ifp;
523 #ifdef ETHER_II
524 error = ef_clone(efl, ETHER_FT_EII);
525 if (error) break;
526 #endif
527 #ifdef ETHER_8023
528 error = ef_clone(efl, ETHER_FT_8023);
529 if (error) break;
530 #endif
531 #ifdef ETHER_8022
532 error = ef_clone(efl, ETHER_FT_8022);
533 if (error) break;
534 #endif
535 #ifdef ETHER_SNAP
536 error = ef_clone(efl, ETHER_FT_SNAP);
537 if (error) break;
538 #endif
539 efcount++;
540 SLIST_INSERT_HEAD(&efdev, efl, el_next);
541 }
542 IFNET_RUNLOCK();
543 if (error) {
544 if (efl)
545 SLIST_INSERT_HEAD(&efdev, efl, el_next);
546 SLIST_FOREACH(efl, &efdev, el_next) {
547 for (d = 0; d < EF_NFT; d++)
548 if (efl->el_units[d])
549 free(efl->el_units[d], M_IFADDR);
550 free(efl, M_IFADDR);
551 }
552 return error;
553 }
554 SLIST_FOREACH(efl, &efdev, el_next) {
555 for (d = 0; d < EF_NFT; d++) {
556 efp = efl->el_units[d];
557 if (efp)
558 ef_attach(efp);
559 }
560 }
561 ef_inputp = ef_input;
562 ef_outputp = ef_output;
563 EFDEBUG("Loaded\n");
564 return 0;
565 }
566
567 static int
568 ef_unload(void)
569 {
570 struct efnet *efp;
571 struct ef_link *efl;
572 int d;
573
574 ef_inputp = NULL;
575 ef_outputp = NULL;
576 SLIST_FOREACH(efl, &efdev, el_next) {
577 for (d = 0; d < EF_NFT; d++) {
578 efp = efl->el_units[d];
579 if (efp) {
580 ef_detach(efp);
581 }
582 }
583 }
584 EFDEBUG("Unloaded\n");
585 return 0;
586 }
587
588 static int
589 if_ef_modevent(module_t mod, int type, void *data)
590 {
591 switch ((modeventtype_t)type) {
592 case MOD_LOAD:
593 return ef_load();
594 case MOD_UNLOAD:
595 return ef_unload();
596 default:
597 return EOPNOTSUPP;
598 }
599 return 0;
600 }
601
602 static moduledata_t if_ef_mod = {
603 "if_ef", if_ef_modevent, NULL
604 };
605
606 DECLARE_MODULE(if_ef, if_ef_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);
Cache object: 41410ac33dd9882e04e03a91e3b10296
|