Merge branch 'vendor/GCC44'
[dragonfly.git] / sys / net / ef / 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: src/sys/net/if_ef.c,v 1.2.2.4 2001/02/22 09:27:04 bp Exp $
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 #include <sys/thread2.h>
43
44 #include <net/ethernet.h>
45 #include <net/if_llc.h>
46 #include <net/if.h>
47 #include <net/if_arp.h>
48 #include <net/if_dl.h>
49 #include <net/if_types.h>
50 #include <net/netisr.h>
51 #include <net/route.h>
52 #include <net/bpf.h>
53
54 #ifdef INET
55 #include <netinet/in.h>
56 #include <netinet/in_var.h>
57 #include <netinet/if_ether.h>
58 #endif
59
60 #ifdef IPX
61 #include <netproto/ipx/ipx.h>
62 #include <netproto/ipx/ipx_if.h>
63 #endif
64
65 /* internal frame types */
66 #define ETHER_FT_EII            0       /* Ethernet_II - default */
67 #define ETHER_FT_8023           1       /* 802.3 (Novell) */
68 #define ETHER_FT_8022           2       /* 802.2 */
69 #define ETHER_FT_SNAP           3       /* SNAP */
70 #define EF_NFT                  4       /* total number of frame types */
71
72 #ifdef EF_DEBUG
73 #define EFDEBUG(format, args...) kprintf("%s: "format, __func__ ,## args)
74 #else
75 #define EFDEBUG(format, args...)
76 #endif
77
78 #define EFERROR(format, args...) kprintf("%s: "format, __func__ ,## args)
79
80 struct efnet {
81         struct arpcom   ef_ac;
82         struct ifnet *  ef_ifp;
83         int             ef_frametype;
84 };
85
86 struct ef_link {
87         SLIST_ENTRY(ef_link) el_next;
88         struct ifnet    *el_ifp;                /* raw device for this clones */
89         struct efnet    *el_units[EF_NFT];      /* our clones */
90 };
91
92 static SLIST_HEAD(ef_link_head, ef_link) efdev = {NULL};
93 static int efcount;
94
95 extern int (*ef_inputp)(struct ifnet*, const struct ether_header *eh,
96                 struct mbuf *m);
97 extern int (*ef_outputp)(struct ifnet *ifp, struct mbuf **mp,
98                 struct sockaddr *dst, short *tp, int *hlen);
99
100 /*
101 static void ef_reset (struct ifnet *);
102 */
103 static int ef_attach(struct efnet *sc);
104 static int ef_detach(struct efnet *sc);
105 static void ef_init(void *);
106 static int ef_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
107 static void ef_start(struct ifnet *);
108 static int ef_input(struct ifnet*, const struct ether_header *, struct mbuf *);
109 static int ef_output(struct ifnet *ifp, struct mbuf **mp,
110                 struct sockaddr *dst, short *tp, int *hlen);
111
112 static int ef_load(void);
113 static int ef_unload(void);
114
115 /*
116  * Install the interface, most of structure initialization done in ef_clone()
117  */
118 static int
119 ef_attach(struct efnet *sc)
120 {
121         struct ifnet *ifp = (struct ifnet*)&sc->ef_ac.ac_if;
122
123         ifp->if_start = ef_start;
124         ifp->if_watchdog = NULL;
125         ifp->if_init = ef_init;
126         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
127         ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
128         /*
129          * Attach the interface
130          */
131         ether_ifattach(ifp, IF_LLADDR(sc->ef_ifp), NULL);
132
133         ifp->if_resolvemulti = 0;
134         ifp->if_type = IFT_XETHER;
135         ifp->if_flags |= IFF_RUNNING;
136
137         EFDEBUG("%s: attached\n", ifp->if_xname);
138         return 1;
139 }
140
141 /*
142  * This is for _testing_only_, just removes interface from interfaces list
143  */
144 static int
145 ef_detach(struct efnet *sc)
146 {
147         ether_ifdetach(&sc->ef_ac.ac_if);
148         return 0;
149 }
150
151 static void
152 ef_init(void *foo __unused)
153 {
154 }
155
156 static int
157 ef_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
158 {
159         struct efnet *sc = ifp->if_softc;
160         struct ifaddr *ifa = (struct ifaddr*)data;
161         int error;
162
163         EFDEBUG("IOCTL %ld for %s\n", cmd, ifp->if_xname);
164         error = 0;
165         crit_enter();
166         switch (cmd) {
167             case SIOCSIFADDR:
168                 if (sc->ef_frametype == ETHER_FT_8023 && 
169                     ifa->ifa_addr->sa_family != AF_IPX) {
170                         error = EAFNOSUPPORT;
171                         break;
172                 }
173                 ifp->if_flags |= IFF_UP; 
174                 /* FALL THROUGH */
175             case SIOCGIFADDR:
176             case SIOCSIFMTU:
177                 error = ether_ioctl(ifp, cmd, data);
178                 break;
179             case SIOCSIFFLAGS:
180                 error = 0;
181                 break;
182             default:
183                 error = EINVAL;
184         }
185         crit_exit();
186         return error;
187 }
188
189 /*
190  * Currently packet prepared in the ether_output(), but this can be a better
191  * place.
192  */
193 static void
194 ef_start(struct ifnet *ifp)
195 {
196         struct efnet *sc = (struct efnet*)ifp->if_softc;
197         struct ifnet *p;
198         struct mbuf *m;
199
200         ifp->if_flags |= IFF_OACTIVE;
201         p = sc->ef_ifp;
202
203         EFDEBUG("\n");
204         for (;;) {
205                 IF_DEQUEUE(&ifp->if_snd, m);
206                 if (m == 0)
207                         break;
208                 BPF_MTAP(ifp, m);
209                 if (IF_QFULL(&p->if_snd)) {
210                         IF_DROP(&p->if_snd);
211                         ifp->if_oerrors++;
212                         m_freem(m);
213                         continue;
214                 }
215                 IF_ENQUEUE(&p->if_snd, m);
216                 if ((p->if_flags & IFF_OACTIVE) == 0) {
217                         p->if_start(p);
218                         ifp->if_opackets++;
219                 }
220         }
221         ifp->if_flags &= ~IFF_OACTIVE;
222         return;
223 }
224
225 /*
226  * Inline functions do not put additional overhead to procedure call or
227  * parameter passing but simplify the code
228  */
229 static __inline int
230 ef_inputEII(struct mbuf *m, struct llc* l, u_short ether_type)
231 {
232         int isr;
233
234         switch(ether_type) {
235 #ifdef IPX
236         case ETHERTYPE_IPX:
237                 isr = NETISR_IPX;
238                 break;
239 #endif
240 #ifdef INET
241         case ETHERTYPE_IP:
242 #ifdef notyet
243                 if (ipflow_fastforward(m))
244                         return (0);
245 #endif
246                 isr = NETISR_IP;
247                 break;
248         case ETHERTYPE_ARP:
249                 isr = NETISR_ARP;
250                 break;
251 #endif
252         default:
253                 return (EPROTONOSUPPORT);
254         }
255         netisr_queue(isr, m);
256         return (0);
257 }
258
259 static __inline int
260 ef_inputSNAP(struct mbuf *m, struct llc* l, u_short ether_type)
261 {
262         int isr;
263
264         switch(ether_type) {
265 #ifdef IPX
266         case ETHERTYPE_IPX:
267                 m_adj(m, 8);
268                 isr = NETISR_IPX;
269                 break;
270 #endif
271         default:
272                 return (EPROTONOSUPPORT);
273         }
274         netisr_queue(isr, m);
275         return (0);
276 }
277
278 static __inline int
279 ef_input8022(struct mbuf *m, struct llc* l, u_short ether_type)
280 {
281         int isr;
282
283         switch(ether_type) {
284 #ifdef IPX
285         case 0xe0:
286                 m_adj(m, 3);
287                 isr = NETISR_IPX;
288                 break;
289 #endif
290         default:
291                 return (EPROTONOSUPPORT);
292         }
293         netisr_queue(isr, m);
294         return (0);
295 }
296
297 /*
298  * Called from ether_input()
299  */
300 static int
301 ef_input(struct ifnet *ifp, const struct ether_header *eh, struct mbuf *m)
302 {
303         u_short ether_type;
304         int ft = -1;
305         struct efnet *efp;
306         struct ifnet *eifp;
307         struct llc *l;
308         struct ef_link *efl;
309         int isr;
310
311         ether_type = ntohs(eh->ether_type);
312         if (ether_type < ETHERMTU) {
313                 l = mtod(m, struct llc*);
314                 if (l->llc_dsap == 0xff && l->llc_ssap == 0xff) {
315                         /* 
316                          * Novell's "802.3" frame
317                          */
318                         ft = ETHER_FT_8023;
319                 } else if (l->llc_dsap == 0xaa && l->llc_ssap == 0xaa) {
320                         /*
321                          * 802.2/SNAP
322                          */
323                         ft = ETHER_FT_SNAP;
324                         ether_type = ntohs(l->llc_un.type_snap.ether_type);
325                 } else if (l->llc_dsap == l->llc_ssap) {
326                         /*
327                          * 802.3/802.2
328                          */
329                         ft = ETHER_FT_8022;
330                         ether_type = l->llc_ssap;
331                 }
332         } else
333                 ft = ETHER_FT_EII;
334
335         if (ft == -1) {
336                 EFDEBUG("Unrecognised ether_type %x\n", ether_type);
337                 return EPROTONOSUPPORT;
338         }
339
340         /*
341          * Check if interface configured for the given frame
342          */
343         efp = NULL;
344         SLIST_FOREACH(efl, &efdev, el_next) {
345                 if (efl->el_ifp == ifp) {
346                         efp = efl->el_units[ft];
347                         break;
348                 }
349         }
350         if (efp == NULL) {
351                 EFDEBUG("Can't find if for %d\n", ft);
352                 return EPROTONOSUPPORT;
353         }
354         eifp = &efp->ef_ac.ac_if;
355         if ((eifp->if_flags & IFF_UP) == 0)
356                 return EPROTONOSUPPORT;
357         eifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
358         m->m_pkthdr.rcvif = eifp;
359
360         if (eifp->if_bpf)
361                 bpf_ptap(eifp->if_bpf, m, eh, ETHER_HDR_LEN);
362
363         /*
364          * Now we ready to adjust mbufs and pass them to protocol intr's
365          */
366         switch(ft) {
367         case ETHER_FT_EII:
368                 return (ef_inputEII(m, l, ether_type));
369                 break;
370 #ifdef IPX
371         case ETHER_FT_8023:             /* only IPX can be here */
372                 isr = NETISR_IPX;
373                 break;
374 #endif
375         case ETHER_FT_SNAP:
376                 return (ef_inputSNAP(m, l, ether_type));
377                 break;
378         case ETHER_FT_8022:
379                 return (ef_input8022(m, l, ether_type));
380                 break;
381         default:
382                 EFDEBUG("No support for frame %d and proto %04x\n",
383                         ft, ether_type);
384                 return (EPROTONOSUPPORT);
385         }
386         netisr_queue(isr, m);
387         return (0);
388 }
389
390 static int
391 ef_output(struct ifnet *ifp, struct mbuf **mp, struct sockaddr *dst, short *tp,
392         int *hlen)
393 {
394         struct efnet *sc = (struct efnet*)ifp->if_softc;
395         struct mbuf *m = *mp;
396         u_char *cp;
397         short type;
398
399         if (ifp->if_type != IFT_XETHER)
400                 return ENETDOWN;
401         switch (sc->ef_frametype) {
402             case ETHER_FT_EII:
403 #ifdef IPX
404                 type = htons(ETHERTYPE_IPX);
405 #else
406                 return EPFNOSUPPORT;
407 #endif
408                 break;
409             case ETHER_FT_8023:
410                 type = htons(m->m_pkthdr.len);
411                 break;
412             case ETHER_FT_8022:
413                 M_PREPEND(m, ETHER_HDR_LEN + 3, MB_WAIT);
414                 if (m == NULL) {
415                         *mp = NULL;
416                         return ENOBUFS;
417                 }
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, MB_WAIT);
437                 if (m == NULL) {
438                         *mp = NULL;
439                         return ENOBUFS;
440                 }
441                 type = htons(m->m_pkthdr.len);
442                 cp = mtod(m, u_char *);
443                 bcopy("\xAA\xAA\x03\x00\x00\x00\x81\x37", cp, 8);
444                 *hlen += 8;
445                 break;
446             default:
447                 return EPFNOSUPPORT;
448         }
449         *mp = m;
450         *tp = type;
451         return 0;
452 }
453
454 /*
455  * Create clone from the given interface
456  */
457 static int
458 ef_clone(struct ef_link *efl, int ft)
459 {
460         struct efnet *efp;
461         struct ifnet *eifp;
462         struct ifnet *ifp = efl->el_ifp;
463
464         efp = (struct efnet*)kmalloc(sizeof(struct efnet), M_IFADDR,
465             M_WAITOK | M_ZERO);
466         efp->ef_ifp = ifp;
467         efp->ef_frametype = ft;
468         eifp = &efp->ef_ac.ac_if;
469         ksnprintf(eifp->if_xname, IFNAMSIZ,
470             "%sf%d", ifp->if_xname, efp->ef_frametype);
471         eifp->if_dname = "ef";
472         eifp->if_dunit = IF_DUNIT_NONE;
473         eifp->if_softc = efp;
474         if (ifp->if_ioctl)
475                 eifp->if_ioctl = ef_ioctl;
476         efl->el_units[ft] = efp;
477         return 0;
478 }
479
480 static int
481 ef_load(void)
482 {
483         struct ifnet *ifp;
484         struct efnet *efp;
485         struct ef_link *efl = NULL;
486         int error = 0, d;
487
488         TAILQ_FOREACH(ifp, &ifnet, if_link) {
489                 if (ifp->if_type != IFT_ETHER) continue;
490                 EFDEBUG("Found interface %s\n", ifp->if_xname);
491                 efl = (struct ef_link*)kmalloc(sizeof(struct ef_link), 
492                     M_IFADDR, M_WAITOK | M_ZERO);
493
494                 efl->el_ifp = ifp;
495 #ifdef ETHER_II
496                 error = ef_clone(efl, ETHER_FT_EII);
497                 if (error) break;
498 #endif
499 #ifdef ETHER_8023
500                 error = ef_clone(efl, ETHER_FT_8023);
501                 if (error) break;
502 #endif
503 #ifdef ETHER_8022
504                 error = ef_clone(efl, ETHER_FT_8022);
505                 if (error) break;
506 #endif
507 #ifdef ETHER_SNAP
508                 error = ef_clone(efl, ETHER_FT_SNAP);
509                 if (error) break;
510 #endif
511                 efcount++;
512                 SLIST_INSERT_HEAD(&efdev, efl, el_next);
513         }
514         if (error) {
515                 if (efl)
516                         SLIST_INSERT_HEAD(&efdev, efl, el_next);
517                 SLIST_FOREACH(efl, &efdev, el_next) {
518                         for (d = 0; d < EF_NFT; d++)
519                                 if (efl->el_units[d])
520                                         kfree(efl->el_units[d], M_IFADDR);
521                         kfree(efl, M_IFADDR);
522                 }
523                 return error;
524         }
525         SLIST_FOREACH(efl, &efdev, el_next) {
526                 for (d = 0; d < EF_NFT; d++) {
527                         efp = efl->el_units[d];
528                         if (efp)
529                                 ef_attach(efp);
530                 }
531         }
532         ef_inputp = ef_input;
533         ef_outputp = ef_output;
534         EFDEBUG("Loaded\n");
535         return 0;
536 }
537
538 static int
539 ef_unload(void)
540 {
541         struct efnet *efp;
542         struct ef_link *efl;
543         int d;
544
545         ef_inputp = NULL;
546         ef_outputp = NULL;
547         SLIST_FOREACH(efl, &efdev, el_next) {
548                 for (d = 0; d < EF_NFT; d++) {
549                         efp = efl->el_units[d];
550                         if (efp) {
551                                 ef_detach(efp);
552                         }
553                 }
554         }
555         EFDEBUG("Unloaded\n");
556         return 0;
557 }
558
559 static int 
560 if_ef_modevent(module_t mod, int type, void *data)
561 {
562         switch ((modeventtype_t)type) {
563             case MOD_LOAD:
564                 return ef_load();
565             case MOD_UNLOAD:
566                 return ef_unload();
567             default:
568                 break;
569         }
570         return 0;
571 }
572
573 static moduledata_t if_ef_mod = {
574         "if_ef", if_ef_modevent, NULL
575 };
576
577 DECLARE_MODULE(if_ef, if_ef_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);