1 /* $NetBSD: if_hippisubr.c,v 1.36 2009/03/18 17:06:51 cegger Exp $ */
4 * Copyright (c) 1982, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: if_hippisubr.c,v 1.36 2009/03/18 17:06:51 cegger Exp $");
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
44 #include <sys/protosw.h>
45 #include <sys/socket.h>
46 #include <sys/ioctl.h>
47 #include <sys/errno.h>
48 #include <sys/syslog.h>
53 #include <net/netisr.h>
54 #include <net/route.h>
55 #include <net/if_llc.h>
56 #include <net/if_dl.h>
57 #include <net/if_types.h>
63 #include <net/if_hippi.h>
65 #include <netinet/in.h>
66 #if defined(INET) || defined(INET6)
67 #include <netinet/in_var.h>
70 #define senderr(e) { error = (e); goto bad;}
73 #define llc_snap llc_un.type_snap
76 static int hippi_output(struct ifnet
*, struct mbuf
*,
77 const struct sockaddr
*, struct rtentry
*);
78 static void hippi_input(struct ifnet
*, struct mbuf
*);
81 * HIPPI output routine.
82 * Encapsulate a packet of type family for the local net.
83 * I don't know anything about the mapping of AppleTalk or OSI
84 * protocols to HIPPI, so I don't include any code for them.
88 hippi_output(struct ifnet
*ifp
, struct mbuf
*m0
, const struct sockaddr
*dst
,
96 struct hippi_header
*hh
;
99 ALTQ_DECL(struct altq_pktattr pktattr
;)
101 if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
))
104 /* HIPPI doesn't really do broadcast or multicast right now */
105 if (m
->m_flags
& (M_BCAST
| M_MCAST
))
106 senderr(EOPNOTSUPP
); /* XXX: some other error? */
108 if ((rt
= rt0
) != NULL
) {
109 if ((rt
->rt_flags
& RTF_UP
) == 0) {
110 if ((rt0
= rt
= rtalloc1(dst
, 1)) != NULL
) {
112 if (rt
->rt_ifp
!= ifp
)
113 return (*rt
->rt_ifp
->if_output
)
116 senderr(EHOSTUNREACH
);
118 if ((rt
->rt_flags
& RTF_GATEWAY
) && dst
->sa_family
!= AF_NS
) {
119 if (rt
->rt_gwroute
== 0)
121 if (((rt
= rt
->rt_gwroute
)->rt_flags
& RTF_UP
) == 0) {
122 rtfree(rt
); rt
= rt0
;
123 lookup
: rt
->rt_gwroute
= rtalloc1(rt
->rt_gateway
, 1);
124 if ((rt
= rt
->rt_gwroute
) == 0)
125 senderr(EHOSTUNREACH
);
126 /* the "G" test below also prevents rt == rt0 */
127 if ((rt
->rt_flags
& RTF_GATEWAY
) ||
128 (rt
->rt_ifp
!= ifp
)) {
131 senderr(EHOSTUNREACH
);
135 if (rt
->rt_flags
& RTF_REJECT
)
136 if (rt
->rt_rmx
.rmx_expire
== 0 || /* XXX: no ARP */
137 time_second
< rt
->rt_rmx
.rmx_expire
)
138 senderr(rt
== rt0
? EHOSTDOWN
: EHOSTUNREACH
);
142 * If the queueing discipline needs packet classification,
143 * do it before prepending link headers.
145 IFQ_CLASSIFY(&ifp
->if_snd
, m
, dst
->sa_family
, &pktattr
);
147 switch (dst
->sa_family
) {
151 const struct sockaddr_dl
*sdl
=
152 satocsdl(rt
->rt_gateway
);
153 if (sdl
->sdl_family
== AF_LINK
&& sdl
->sdl_alen
!= 0)
154 memcpy(&ifield
, CLLADDR(sdl
), sizeof(ifield
));
156 if (!ifield
) /* XXX: bogus check, but helps us get going */
157 senderr(EHOSTUNREACH
);
158 htype
= htons(ETHERTYPE_IP
);
165 const struct sockaddr_dl
*sdl
=
166 satocsdl(rt
->rt_gateway
);
167 if (sdl
->sdl_family
== AF_LINK
&& sdl
->sdl_alen
!= 0)
168 memcpy(&ifield
, CLLADDR(sdl
), sizeof(ifield
));
170 if (!ifield
) /* XXX: bogus check, but helps us get going */
171 senderr(EHOSTUNREACH
);
172 htype
= htons(ETHERTYPE_IPV6
);
177 printf("%s: can't handle af%d\n", ifp
->if_xname
,
179 senderr(EAFNOSUPPORT
);
184 M_PREPEND(m
, sizeof (struct llc
), M_DONTWAIT
);
187 l
= mtod(m
, struct llc
*);
188 l
->llc_control
= LLC_UI
;
189 l
->llc_dsap
= l
->llc_ssap
= LLC_SNAP_LSAP
;
190 l
->llc_snap
.org_code
[0] = l
->llc_snap
.org_code
[1] =
191 l
->llc_snap
.org_code
[2] = 0;
192 memcpy((void *) &l
->llc_snap
.ether_type
, (void *) &htype
,
196 d2_len
= m
->m_pkthdr
.len
;
199 * Add local net header. If no space in first mbuf,
203 M_PREPEND(m
, sizeof (struct hippi_header
) + 8, M_DONTWAIT
);
206 cci
= mtod(m
, uint32_t *);
207 memset(cci
, 0, sizeof(struct hippi_header
) + 8);
210 hh
= (struct hippi_header
*) &cci
[2];
211 hh
->hi_fp
.fp_ulp
= HIPPI_ULP_802
;
212 hh
->hi_fp
.fp_flags
= HIPPI_FP_D1_PRESENT
;
213 hh
->hi_fp
.fp_offsets
= htons(sizeof(struct hippi_le
));
214 hh
->hi_fp
.fp_d2_len
= htonl(d2_len
);
216 /* Pad out the D2 area to end on a quadword (64-bit) boundry. */
218 if (d2_len
% 8 != 0) {
219 static uint32_t buffer
[2] = {0, 0};
220 m_copyback(m
, m
->m_pkthdr
.len
, 8 - d2_len
% 8, (void *) buffer
);
223 return ifq_enqueue(ifp
, m ALTQ_COMMA
ALTQ_DECL(&pktattr
));
232 * Process a received HIPPI packet;
233 * the packet is in the mbuf chain m with
238 hippi_input(struct ifnet
*ifp
, struct mbuf
*m
)
243 struct hippi_header
*hh
;
246 if ((ifp
->if_flags
& IFF_UP
) == 0) {
251 /* XXX: need to check flags and drop if bogus! */
253 hh
= mtod(m
, struct hippi_header
*);
255 ifp
->if_ibytes
+= m
->m_pkthdr
.len
;
256 if (hh
->hi_le
.le_dest_addr
[0] & 1) {
257 if (memcmp(etherbroadcastaddr
, hh
->hi_le
.le_dest_addr
,
258 sizeof(etherbroadcastaddr
)) == 0)
259 m
->m_flags
|= M_BCAST
;
261 m
->m_flags
|= M_MCAST
;
263 if (m
->m_flags
& (M_BCAST
|M_MCAST
))
266 /* Skip past the HIPPI header. */
267 m_adj(m
, sizeof(struct hippi_header
));
269 l
= mtod(m
, struct llc
*);
270 if (l
->llc_dsap
!= LLC_SNAP_LSAP
) {
274 htype
= ntohs(l
->llc_snap
.ether_type
);
279 schednetisr(NETISR_IP
);
285 schednetisr(NETISR_IPV6
);
304 * Handle packet from HIPPI that has no MAC header
309 hippi_ip_input(struct ifnet
*ifp
, struct mbuf
*m
)
314 schednetisr(NETISR_IP
);
328 * Perform common duties while attaching to interface list
331 hippi_ifattach(struct ifnet
*ifp
, void *lla
)
334 ifp
->if_type
= IFT_HIPPI
;
335 ifp
->if_hdrlen
= sizeof(struct hippi_header
) + 8; /* add CCI */
336 ifp
->if_dlt
= DLT_HIPPI
;
337 ifp
->if_mtu
= HIPPIMTU
;
338 ifp
->if_output
= hippi_output
;
339 ifp
->if_input
= hippi_input
;
340 ifp
->if_baudrate
= IF_Mbps(800); /* XXX double-check */
342 if_set_sadl(ifp
, lla
, 6, true);
345 bpfattach(ifp
, DLT_HIPPI
, sizeof(struct hippi_header
));