2 * Copyright (c) 1999, 2000 Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $FreeBSD: src/sys/net/if_ef.c,v 1.2.2.4 2001/02/22 09:27:04 bp Exp $
27 * $DragonFly: src/sys/net/ef/if_ef.c,v 1.27 2008/07/27 10:06:57 sephe Exp $
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/sockio.h>
37 #include <sys/malloc.h>
39 #include <sys/socket.h>
40 #include <sys/syslog.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/thread2.h>
45 #include <net/ethernet.h>
46 #include <net/if_llc.h>
48 #include <net/if_arp.h>
49 #include <net/if_dl.h>
50 #include <net/if_types.h>
51 #include <net/netisr.h>
52 #include <net/route.h>
56 #include <netinet/in.h>
57 #include <netinet/in_var.h>
58 #include <netinet/if_ether.h>
62 #include <netproto/ipx/ipx.h>
63 #include <netproto/ipx/ipx_if.h>
66 /* internal frame types */
67 #define ETHER_FT_EII 0 /* Ethernet_II - default */
68 #define ETHER_FT_8023 1 /* 802.3 (Novell) */
69 #define ETHER_FT_8022 2 /* 802.2 */
70 #define ETHER_FT_SNAP 3 /* SNAP */
71 #define EF_NFT 4 /* total number of frame types */
74 #define EFDEBUG(format, args...) kprintf("%s: "format, __func__ ,## args)
76 #define EFDEBUG(format, args...)
79 #define EFERROR(format, args...) kprintf("%s: "format, __func__ ,## args)
83 struct ifnet
* ef_ifp
;
88 SLIST_ENTRY(ef_link
) el_next
;
89 struct ifnet
*el_ifp
; /* raw device for this clones */
90 struct efnet
*el_units
[EF_NFT
]; /* our clones */
93 static SLIST_HEAD(ef_link_head
, ef_link
) efdev
= {NULL
};
96 extern int (*ef_inputp
)(struct ifnet
*, const struct ether_header
*eh
,
98 extern int (*ef_outputp
)(struct ifnet
*ifp
, struct mbuf
**mp
,
99 struct sockaddr
*dst
, short *tp
, int *hlen
);
102 static void ef_reset (struct ifnet *);
104 static int ef_attach(struct efnet
*sc
);
105 static int ef_detach(struct efnet
*sc
);
106 static void ef_init(void *);
107 static int ef_ioctl(struct ifnet
*, u_long
, caddr_t
, struct ucred
*);
108 static void ef_start(struct ifnet
*);
109 static int ef_input(struct ifnet
*, const struct ether_header
*, struct mbuf
*);
110 static int ef_output(struct ifnet
*ifp
, struct mbuf
**mp
,
111 struct sockaddr
*dst
, short *tp
, int *hlen
);
113 static int ef_load(void);
114 static int ef_unload(void);
117 * Install the interface, most of structure initialization done in ef_clone()
120 ef_attach(struct efnet
*sc
)
122 struct ifnet
*ifp
= (struct ifnet
*)&sc
->ef_ac
.ac_if
;
124 ifp
->if_start
= ef_start
;
125 ifp
->if_watchdog
= NULL
;
126 ifp
->if_init
= ef_init
;
127 ifp
->if_snd
.ifq_maxlen
= IFQ_MAXLEN
;
128 ifp
->if_flags
= (IFF_BROADCAST
| IFF_SIMPLEX
| IFF_MULTICAST
);
130 * Attach the interface
132 ether_ifattach(ifp
, IF_LLADDR(sc
->ef_ifp
), NULL
);
134 ifp
->if_resolvemulti
= 0;
135 ifp
->if_type
= IFT_XETHER
;
136 ifp
->if_flags
|= IFF_RUNNING
;
138 EFDEBUG("%s: attached\n", ifp
->if_xname
);
143 * This is for _testing_only_, just removes interface from interfaces list
146 ef_detach(struct efnet
*sc
)
148 ether_ifdetach(&sc
->ef_ac
.ac_if
);
153 ef_init(void *foo __unused
)
158 ef_ioctl(struct ifnet
*ifp
, u_long cmd
, caddr_t data
, struct ucred
*cr
)
160 struct efnet
*sc
= ifp
->if_softc
;
161 struct ifaddr
*ifa
= (struct ifaddr
*)data
;
164 EFDEBUG("IOCTL %ld for %s\n", cmd
, ifp
->if_xname
);
169 if (sc
->ef_frametype
== ETHER_FT_8023
&&
170 ifa
->ifa_addr
->sa_family
!= AF_IPX
) {
171 error
= EAFNOSUPPORT
;
174 ifp
->if_flags
|= IFF_UP
;
178 error
= ether_ioctl(ifp
, cmd
, data
);
191 * Currently packet prepared in the ether_output(), but this can be a better
195 ef_start(struct ifnet
*ifp
)
197 struct efnet
*sc
= (struct efnet
*)ifp
->if_softc
;
201 ifp
->if_flags
|= IFF_OACTIVE
;
206 IF_DEQUEUE(&ifp
->if_snd
, m
);
210 if (IF_QFULL(&p
->if_snd
)) {
216 IF_ENQUEUE(&p
->if_snd
, m
);
217 if ((p
->if_flags
& IFF_OACTIVE
) == 0) {
222 ifp
->if_flags
&= ~IFF_OACTIVE
;
227 * Inline functions do not put additional overhead to procedure call or
228 * parameter passing but simplify the code
231 ef_inputEII(struct mbuf
*m
, struct llc
* l
, u_short ether_type
)
244 if (ipflow_fastforward(m
))
254 return (EPROTONOSUPPORT
);
256 netisr_dispatch(isr
, m
);
261 ef_inputSNAP(struct mbuf
*m
, struct llc
* l
, u_short ether_type
)
273 return (EPROTONOSUPPORT
);
275 netisr_dispatch(isr
, m
);
280 ef_input8022(struct mbuf
*m
, struct llc
* l
, u_short ether_type
)
292 return (EPROTONOSUPPORT
);
294 netisr_dispatch(isr
, m
);
299 * Called from ether_input()
302 ef_input(struct ifnet
*ifp
, const struct ether_header
*eh
, struct mbuf
*m
)
312 ether_type
= ntohs(eh
->ether_type
);
313 if (ether_type
< ETHERMTU
) {
314 l
= mtod(m
, struct llc
*);
315 if (l
->llc_dsap
== 0xff && l
->llc_ssap
== 0xff) {
317 * Novell's "802.3" frame
320 } else if (l
->llc_dsap
== 0xaa && l
->llc_ssap
== 0xaa) {
325 ether_type
= ntohs(l
->llc_un
.type_snap
.ether_type
);
326 } else if (l
->llc_dsap
== l
->llc_ssap
) {
331 ether_type
= l
->llc_ssap
;
337 EFDEBUG("Unrecognised ether_type %x\n", ether_type
);
338 return EPROTONOSUPPORT
;
342 * Check if interface configured for the given frame
345 SLIST_FOREACH(efl
, &efdev
, el_next
) {
346 if (efl
->el_ifp
== ifp
) {
347 efp
= efl
->el_units
[ft
];
352 EFDEBUG("Can't find if for %d\n", ft
);
353 return EPROTONOSUPPORT
;
355 eifp
= &efp
->ef_ac
.ac_if
;
356 if ((eifp
->if_flags
& IFF_UP
) == 0)
357 return EPROTONOSUPPORT
;
358 eifp
->if_ibytes
+= m
->m_pkthdr
.len
+ sizeof (*eh
);
359 m
->m_pkthdr
.rcvif
= eifp
;
362 bpf_ptap(eifp
->if_bpf
, m
, eh
, ETHER_HDR_LEN
);
365 * Now we ready to adjust mbufs and pass them to protocol intr's
369 return (ef_inputEII(m
, l
, ether_type
));
372 case ETHER_FT_8023
: /* only IPX can be here */
377 return (ef_inputSNAP(m
, l
, ether_type
));
380 return (ef_input8022(m
, l
, ether_type
));
383 EFDEBUG("No support for frame %d and proto %04x\n",
385 return (EPROTONOSUPPORT
);
387 netisr_dispatch(isr
, m
);
392 ef_output(struct ifnet
*ifp
, struct mbuf
**mp
, struct sockaddr
*dst
, short *tp
,
395 struct efnet
*sc
= (struct efnet
*)ifp
->if_softc
;
396 struct mbuf
*m
= *mp
;
400 if (ifp
->if_type
!= IFT_XETHER
)
402 switch (sc
->ef_frametype
) {
405 type
= htons(ETHERTYPE_IPX
);
411 type
= htons(m
->m_pkthdr
.len
);
414 M_PREPEND(m
, ETHER_HDR_LEN
+ 3, MB_WAIT
);
420 * Ensure that ethernet header and next three bytes
421 * will fit into single mbuf
423 m
= m_pullup(m
, ETHER_HDR_LEN
+ 3);
428 m_adj(m
, ETHER_HDR_LEN
);
429 type
= htons(m
->m_pkthdr
.len
);
430 cp
= mtod(m
, u_char
*);
437 M_PREPEND(m
, 8, MB_WAIT
);
442 type
= htons(m
->m_pkthdr
.len
);
443 cp
= mtod(m
, u_char
*);
444 bcopy("\xAA\xAA\x03\x00\x00\x00\x81\x37", cp
, 8);
456 * Create clone from the given interface
459 ef_clone(struct ef_link
*efl
, int ft
)
463 struct ifnet
*ifp
= efl
->el_ifp
;
465 efp
= (struct efnet
*)kmalloc(sizeof(struct efnet
), M_IFADDR
,
468 efp
->ef_frametype
= ft
;
469 eifp
= &efp
->ef_ac
.ac_if
;
470 ksnprintf(eifp
->if_xname
, IFNAMSIZ
,
471 "%sf%d", ifp
->if_xname
, efp
->ef_frametype
);
472 eifp
->if_dname
= "ef";
473 eifp
->if_dunit
= IF_DUNIT_NONE
;
474 eifp
->if_softc
= efp
;
476 eifp
->if_ioctl
= ef_ioctl
;
477 efl
->el_units
[ft
] = efp
;
486 struct ef_link
*efl
= NULL
;
489 TAILQ_FOREACH(ifp
, &ifnet
, if_link
) {
490 if (ifp
->if_type
!= IFT_ETHER
) continue;
491 EFDEBUG("Found interface %s\n", ifp
->if_xname
);
492 efl
= (struct ef_link
*)kmalloc(sizeof(struct ef_link
),
493 M_IFADDR
, M_WAITOK
| M_ZERO
);
497 error
= ef_clone(efl
, ETHER_FT_EII
);
501 error
= ef_clone(efl
, ETHER_FT_8023
);
505 error
= ef_clone(efl
, ETHER_FT_8022
);
509 error
= ef_clone(efl
, ETHER_FT_SNAP
);
513 SLIST_INSERT_HEAD(&efdev
, efl
, el_next
);
517 SLIST_INSERT_HEAD(&efdev
, efl
, el_next
);
518 SLIST_FOREACH(efl
, &efdev
, el_next
) {
519 for (d
= 0; d
< EF_NFT
; d
++)
520 if (efl
->el_units
[d
])
521 kfree(efl
->el_units
[d
], M_IFADDR
);
522 kfree(efl
, M_IFADDR
);
526 SLIST_FOREACH(efl
, &efdev
, el_next
) {
527 for (d
= 0; d
< EF_NFT
; d
++) {
528 efp
= efl
->el_units
[d
];
533 ef_inputp
= ef_input
;
534 ef_outputp
= ef_output
;
548 SLIST_FOREACH(efl
, &efdev
, el_next
) {
549 for (d
= 0; d
< EF_NFT
; d
++) {
550 efp
= efl
->el_units
[d
];
556 EFDEBUG("Unloaded\n");
561 if_ef_modevent(module_t mod
, int type
, void *data
)
563 switch ((modeventtype_t
)type
) {
574 static moduledata_t if_ef_mod
= {
575 "if_ef", if_ef_modevent
, NULL
578 DECLARE_MODULE(if_ef
, if_ef_mod
, SI_SUB_PSEUDO
, SI_ORDER_MIDDLE
);