]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/net/if_ef.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / 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/bpf.h>
51 #include <net/vnet.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 ifnet    *ef_ifp;
90         struct ifnet    *ef_pifp;
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 = sc->ef_ifp;
129
130         ifp->if_start = ef_start;
131         ifp->if_init = ef_init;
132         ifp->if_snd.ifq_maxlen = ifqmaxlen;
133         ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
134         /*
135          * Attach the interface
136          */
137         ether_ifattach(ifp, IF_LLADDR(sc->ef_pifp));
138
139         ifp->if_resolvemulti = 0;
140         ifp->if_type = IFT_XETHER;
141         ifp->if_drv_flags |= IFF_DRV_RUNNING;
142
143         EFDEBUG("%s: attached\n", ifp->if_xname);
144         return 1;
145 }
146
147 /*
148  * This is for _testing_only_, just removes interface from interfaces list
149  */
150 static int
151 ef_detach(struct efnet *sc)
152 {
153         struct ifnet *ifp = sc->ef_ifp;
154         int s;
155
156         s = splimp();
157
158         ether_ifdetach(ifp);
159         if_free(ifp);
160
161         splx(s);
162         return 0;
163 }
164
165 static void
166 ef_init(void *foo) {
167         return;
168 }
169
170 static int
171 ef_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
172 {
173         struct efnet *sc = ifp->if_softc;
174         struct ifaddr *ifa = (struct ifaddr*)data;
175         int s, error;
176
177         EFDEBUG("IOCTL %ld for %s\n", cmd, ifp->if_xname);
178         error = 0;
179         s = splimp();
180         switch (cmd) {
181             case SIOCSIFFLAGS:
182                 error = 0;
183                 break;
184             case SIOCSIFADDR:
185                 if (sc->ef_frametype == ETHER_FT_8023 && 
186                     ifa->ifa_addr->sa_family != AF_IPX) {
187                         error = EAFNOSUPPORT;
188                         break;
189                 }
190                 ifp->if_flags |= IFF_UP; 
191                 /* FALL THROUGH */
192             default:
193                 error = ether_ioctl(ifp, cmd, data);
194                 break;
195         }
196         splx(s);
197         return error;
198 }
199
200 /*
201  * Currently packet prepared in the ether_output(), but this can be a better
202  * place.
203  */
204 static void
205 ef_start(struct ifnet *ifp)
206 {
207         struct efnet *sc = (struct efnet*)ifp->if_softc;
208         struct ifnet *p;
209         struct mbuf *m;
210         int error;
211
212         ifp->if_drv_flags |= IFF_DRV_OACTIVE;
213         p = sc->ef_pifp;
214
215         EFDEBUG("\n");
216         for (;;) {
217                 IF_DEQUEUE(&ifp->if_snd, m);
218                 if (m == 0)
219                         break;
220                 BPF_MTAP(ifp, m);
221                 error = p->if_transmit(p, m);
222                 if (error) {
223                         ifp->if_oerrors++;
224                         continue;
225                 }
226                 ifp->if_opackets++;
227         }
228         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
229         return;
230 }
231
232 /*
233  * Inline functions do not put additional overhead to procedure call or
234  * parameter passing but simplify the code
235  */
236 static int __inline
237 ef_inputEII(struct mbuf *m, struct ether_header *eh, u_short ether_type)
238 {
239         int isr;
240
241         switch(ether_type) {
242 #ifdef IPX
243         case ETHERTYPE_IPX:
244                 isr = NETISR_IPX;
245                 break;
246 #endif
247 #ifdef INET
248         case ETHERTYPE_IP:
249                 if ((m = ip_fastforward(m)) == NULL)
250                         return (0);
251                 isr = NETISR_IP;
252                 break;
253
254         case ETHERTYPE_ARP:
255                 isr = NETISR_ARP;
256                 break;
257 #endif
258         default:
259                 return (EPROTONOSUPPORT);
260         }
261         netisr_dispatch(isr, m);
262         return (0);
263 }
264
265 static int __inline
266 ef_inputSNAP(struct mbuf *m, struct ether_header *eh, struct llc* l,
267         u_short ether_type)
268 {
269         int isr;
270
271         switch(ether_type) {
272 #ifdef IPX
273         case ETHERTYPE_IPX:
274                 m_adj(m, 8);
275                 isr = NETISR_IPX;
276                 break;
277 #endif
278         default:
279                 return (EPROTONOSUPPORT);
280         }
281         netisr_dispatch(isr, m);
282         return (0);
283 }
284
285 static int __inline
286 ef_input8022(struct mbuf *m, struct ether_header *eh, struct llc* l,
287         u_short ether_type)
288 {
289         int isr;
290
291         switch(ether_type) {
292 #ifdef IPX
293         case 0xe0:
294                 m_adj(m, 3);
295                 isr = NETISR_IPX;
296                 break;
297 #endif
298         default:
299                 return (EPROTONOSUPPORT);
300         }
301         netisr_dispatch(isr, m);
302         return (0);
303 }
304
305 /*
306  * Called from ether_input()
307  */
308 static int
309 ef_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m)
310 {
311         u_short ether_type;
312         int ft = -1;
313         struct efnet *efp;
314         struct ifnet *eifp;
315         struct llc *l;
316         struct ef_link *efl;
317         int isr;
318
319         ether_type = ntohs(eh->ether_type);
320         l = NULL;
321         if (ether_type < ETHERMTU) {
322                 l = mtod(m, struct llc*);
323                 if (l->llc_dsap == 0xff && l->llc_ssap == 0xff) {
324                         /* 
325                          * Novell's "802.3" frame
326                          */
327                         ft = ETHER_FT_8023;
328                 } else if (l->llc_dsap == 0xaa && l->llc_ssap == 0xaa) {
329                         /*
330                          * 802.2/SNAP
331                          */
332                         ft = ETHER_FT_SNAP;
333                         ether_type = ntohs(l->llc_un.type_snap.ether_type);
334                 } else if (l->llc_dsap == l->llc_ssap) {
335                         /*
336                          * 802.3/802.2
337                          */
338                         ft = ETHER_FT_8022;
339                         ether_type = l->llc_ssap;
340                 }
341         } else
342                 ft = ETHER_FT_EII;
343
344         if (ft == -1) {
345                 EFDEBUG("Unrecognised ether_type %x\n", ether_type);
346                 return EPROTONOSUPPORT;
347         }
348
349         /*
350          * Check if interface configured for the given frame
351          */
352         efp = NULL;
353         SLIST_FOREACH(efl, &efdev, el_next) {
354                 if (efl->el_ifp == ifp) {
355                         efp = efl->el_units[ft];
356                         break;
357                 }
358         }
359         if (efp == NULL) {
360                 EFDEBUG("Can't find if for %d\n", ft);
361                 return EPROTONOSUPPORT;
362         }
363         eifp = efp->ef_ifp;
364         if ((eifp->if_flags & IFF_UP) == 0)
365                 return EPROTONOSUPPORT;
366         eifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
367         m->m_pkthdr.rcvif = eifp;
368
369         BPF_MTAP2(eifp, eh, ETHER_HDR_LEN, m);
370         /*
371          * Now we ready to adjust mbufs and pass them to protocol intr's
372          */
373         switch(ft) {
374         case ETHER_FT_EII:
375                 return (ef_inputEII(m, eh, ether_type));
376 #ifdef IPX
377         case ETHER_FT_8023:             /* only IPX can be here */
378                 isr = NETISR_IPX;
379                 break;
380 #endif
381         case ETHER_FT_SNAP:
382                 return (ef_inputSNAP(m, eh, l, ether_type));
383         case ETHER_FT_8022:
384                 return (ef_input8022(m, eh, l, ether_type));
385         default:
386                 EFDEBUG("No support for frame %d and proto %04x\n",
387                         ft, ether_type);
388                 return (EPROTONOSUPPORT);
389         }
390         netisr_dispatch(isr, m);
391         return (0);
392 }
393
394 static int
395 ef_output(struct ifnet *ifp, struct mbuf **mp, struct sockaddr *dst, short *tp,
396         int *hlen)
397 {
398         struct efnet *sc = (struct efnet*)ifp->if_softc;
399         struct mbuf *m = *mp;
400         u_char *cp;
401         short type;
402
403         if (ifp->if_type != IFT_XETHER)
404                 return ENETDOWN;
405         switch (sc->ef_frametype) {
406             case ETHER_FT_EII:
407 #ifdef IPX
408                 type = htons(ETHERTYPE_IPX);
409 #else
410                 return EPFNOSUPPORT;
411 #endif
412                 break;
413             case ETHER_FT_8023:
414                 type = htons(m->m_pkthdr.len);
415                 break;
416             case ETHER_FT_8022:
417                 M_PREPEND(m, ETHER_HDR_LEN + 3, M_WAIT);
418                 /*
419                  * Ensure that ethernet header and next three bytes
420                  * will fit into single mbuf
421                  */
422                 m = m_pullup(m, ETHER_HDR_LEN + 3);
423                 if (m == NULL) {
424                         *mp = NULL;
425                         return ENOBUFS;
426                 }
427                 m_adj(m, ETHER_HDR_LEN);
428                 type = htons(m->m_pkthdr.len);
429                 cp = mtod(m, u_char *);
430                 *cp++ = 0xE0;
431                 *cp++ = 0xE0;
432                 *cp++ = 0x03;
433                 *hlen += 3;
434                 break;
435             case ETHER_FT_SNAP:
436                 M_PREPEND(m, 8, M_WAIT);
437                 type = htons(m->m_pkthdr.len);
438                 cp = mtod(m, u_char *);
439                 bcopy("\xAA\xAA\x03\x00\x00\x00\x81\x37", cp, 8);
440                 *hlen += 8;
441                 break;
442             default:
443                 return EPFNOSUPPORT;
444         }
445         *mp = m;
446         *tp = type;
447         return 0;
448 }
449
450 /*
451  * Create clone from the given interface
452  */
453 static int
454 ef_clone(struct ef_link *efl, int ft)
455 {
456         struct efnet *efp;
457         struct ifnet *eifp;
458         struct ifnet *ifp = efl->el_ifp;
459
460         efp = (struct efnet*)malloc(sizeof(struct efnet), M_IFADDR,
461             M_WAITOK | M_ZERO);
462         if (efp == NULL)
463                 return ENOMEM;
464         efp->ef_pifp = ifp;
465         efp->ef_frametype = ft;
466         eifp = efp->ef_ifp = if_alloc(IFT_ETHER);
467         if (eifp == NULL) {
468                 free(efp, M_IFADDR);
469                 return (ENOSPC);
470         }
471         snprintf(eifp->if_xname, IFNAMSIZ,
472             "%sf%d", ifp->if_xname, efp->ef_frametype);
473         eifp->if_dname = "ef";
474         eifp->if_dunit = IF_DUNIT_NONE;
475         eifp->if_softc = efp;
476         if (ifp->if_ioctl)
477                 eifp->if_ioctl = ef_ioctl;
478         efl->el_units[ft] = efp;
479         return 0;
480 }
481
482 static int
483 ef_load(void)
484 {
485         VNET_ITERATOR_DECL(vnet_iter);
486         struct ifnet *ifp;
487         struct efnet *efp;
488         struct ef_link *efl = NULL, *efl_temp;
489         int error = 0, d;
490
491         VNET_LIST_RLOCK();
492         VNET_FOREACH(vnet_iter) {
493                 CURVNET_SET(vnet_iter);
494
495                 /*
496                  * XXXRW: The following loop walks the ifnet list while
497                  * modifying it, something not well-supported by ifnet
498                  * locking.  To avoid lock upgrade/recursion issues, manually
499                  * acquire a write lock of ifnet_sxlock here, rather than a
500                  * read lock, so that when if_alloc() recurses the lock, we
501                  * don't panic.  This structure, in which if_ef automatically
502                  * attaches to all ethernet interfaces, should be replaced
503                  * with a model like that found in if_vlan, in which
504                  * interfaces are explicitly configured, which would avoid
505                  * this (and other) problems.
506                  */
507                 sx_xlock(&ifnet_sxlock);
508                 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
509                         if (ifp->if_type != IFT_ETHER) continue;
510                         EFDEBUG("Found interface %s\n", ifp->if_xname);
511                         efl = (struct ef_link*)malloc(sizeof(struct ef_link), 
512                             M_IFADDR, M_WAITOK | M_ZERO);
513                         if (efl == NULL) {
514                                 error = ENOMEM;
515                                 break;
516                         }
517
518                         efl->el_ifp = ifp;
519 #ifdef ETHER_II
520                         error = ef_clone(efl, ETHER_FT_EII);
521                         if (error) break;
522 #endif
523 #ifdef ETHER_8023
524                         error = ef_clone(efl, ETHER_FT_8023);
525                         if (error) break;
526 #endif
527 #ifdef ETHER_8022
528                         error = ef_clone(efl, ETHER_FT_8022);
529                         if (error) break;
530 #endif
531 #ifdef ETHER_SNAP
532                         error = ef_clone(efl, ETHER_FT_SNAP);
533                         if (error) break;
534 #endif
535                         efcount++;
536                         SLIST_INSERT_HEAD(&efdev, efl, el_next);
537                 }
538                 sx_xunlock(&ifnet_sxlock);
539                 CURVNET_RESTORE();
540         }
541         VNET_LIST_RUNLOCK();
542         if (error) {
543                 if (efl)
544                         SLIST_INSERT_HEAD(&efdev, efl, el_next);
545                 SLIST_FOREACH_SAFE(efl, &efdev, el_next, efl_temp) {
546                         for (d = 0; d < EF_NFT; d++)
547                                 if (efl->el_units[d]) {
548                                         if (efl->el_units[d]->ef_pifp != NULL)
549                                                 if_free(efl->el_units[d]->ef_pifp);
550                                         free(efl->el_units[d], M_IFADDR);
551                                 }
552                         free(efl, M_IFADDR);
553                 }
554                 return error;
555         }
556         SLIST_FOREACH(efl, &efdev, el_next) {
557                 for (d = 0; d < EF_NFT; d++) {
558                         efp = efl->el_units[d];
559                         if (efp)
560                                 ef_attach(efp);
561                 }
562         }
563         ef_inputp = ef_input;
564         ef_outputp = ef_output;
565         EFDEBUG("Loaded\n");
566         return 0;
567 }
568
569 static int
570 ef_unload(void)
571 {
572         struct efnet *efp;
573         struct ef_link *efl;
574         int d;
575
576         ef_inputp = NULL;
577         ef_outputp = NULL;
578         SLIST_FOREACH(efl, &efdev, el_next) {
579                 for (d = 0; d < EF_NFT; d++) {
580                         efp = efl->el_units[d];
581                         if (efp) {
582                                 ef_detach(efp);
583                         }
584                 }
585         }
586         EFDEBUG("Unloaded\n");
587         return 0;
588 }
589
590 static int 
591 if_ef_modevent(module_t mod, int type, void *data)
592 {
593         switch ((modeventtype_t)type) {
594             case MOD_LOAD:
595                 return ef_load();
596             case MOD_UNLOAD:
597                 return ef_unload();
598             default:
599                 return EOPNOTSUPP;
600         }
601         return 0;
602 }
603
604 static moduledata_t if_ef_mod = {
605         "if_ef", if_ef_modevent, NULL
606 };
607
608 DECLARE_MODULE(if_ef, if_ef_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);