Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / net / if_hippisubr.c
blob06f10d34edf050b19ef2903930dbcba0a1ff91fa
1 /* $NetBSD: if_hippisubr.c,v 1.36 2009/03/18 17:06:51 cegger Exp $ */
3 /*
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
9 * are met:
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
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: if_hippisubr.c,v 1.36 2009/03/18 17:06:51 cegger Exp $");
35 #include "opt_inet.h"
37 #include "bpfilter.h"
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <sys/mbuf.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>
50 #include <sys/cpu.h>
52 #include <net/if.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>
59 #if NBPFILTER > 0
60 #include <net/bpf.h>
61 #endif
63 #include <net/if_hippi.h>
65 #include <netinet/in.h>
66 #if defined(INET) || defined(INET6)
67 #include <netinet/in_var.h>
68 #endif
70 #define senderr(e) { error = (e); goto bad;}
72 #ifndef llc_snap
73 #define llc_snap llc_un.type_snap
74 #endif
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.
87 static int
88 hippi_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst,
89 struct rtentry *rt0)
91 uint16_t htype;
92 uint32_t ifield = 0;
93 int error = 0;
94 struct mbuf *m = m0;
95 struct rtentry *rt;
96 struct hippi_header *hh;
97 uint32_t *cci;
98 uint32_t d2_len;
99 ALTQ_DECL(struct altq_pktattr pktattr;)
101 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
102 senderr(ENETDOWN);
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) {
111 rt->rt_refcnt--;
112 if (rt->rt_ifp != ifp)
113 return (*rt->rt_ifp->if_output)
114 (ifp, m0, dst, rt);
115 } else
116 senderr(EHOSTUNREACH);
118 if ((rt->rt_flags & RTF_GATEWAY) && dst->sa_family != AF_NS) {
119 if (rt->rt_gwroute == 0)
120 goto lookup;
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)) {
129 rt->rt_refcnt--;
130 rt0->rt_gwroute = 0;
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) {
148 #ifdef INET
149 case AF_INET:
150 if (rt) {
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);
159 break;
160 #endif
162 #ifdef INET6
163 case AF_INET6:
164 if (rt) {
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);
173 break;
174 #endif
176 default:
177 printf("%s: can't handle af%d\n", ifp->if_xname,
178 dst->sa_family);
179 senderr(EAFNOSUPPORT);
182 if (htype != 0) {
183 struct llc *l;
184 M_PREPEND(m, sizeof (struct llc), M_DONTWAIT);
185 if (m == 0)
186 senderr(ENOBUFS);
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,
193 sizeof(uint16_t));
196 d2_len = m->m_pkthdr.len;
199 * Add local net header. If no space in first mbuf,
200 * allocate another.
203 M_PREPEND(m, sizeof (struct hippi_header) + 8, M_DONTWAIT);
204 if (m == 0)
205 senderr(ENOBUFS);
206 cci = mtod(m, uint32_t *);
207 memset(cci, 0, sizeof(struct hippi_header) + 8);
208 cci[0] = 0;
209 cci[1] = ifield;
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));
225 bad:
226 if (m)
227 m_freem(m);
228 return (error);
232 * Process a received HIPPI packet;
233 * the packet is in the mbuf chain m with
234 * the HIPPI header.
237 static void
238 hippi_input(struct ifnet *ifp, struct mbuf *m)
240 struct ifqueue *inq;
241 struct llc *l;
242 uint16_t htype;
243 struct hippi_header *hh;
244 int s;
246 if ((ifp->if_flags & IFF_UP) == 0) {
247 m_freem(m);
248 return;
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;
260 else
261 m->m_flags |= M_MCAST;
263 if (m->m_flags & (M_BCAST|M_MCAST))
264 ifp->if_imcasts++;
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) {
271 m_freem(m);
272 return;
274 htype = ntohs(l->llc_snap.ether_type);
275 m_adj(m, 8);
276 switch (htype) {
277 #ifdef INET
278 case ETHERTYPE_IP:
279 schednetisr(NETISR_IP);
280 inq = &ipintrq;
281 break;
282 #endif
283 #ifdef INET6
284 case ETHERTYPE_IPV6:
285 schednetisr(NETISR_IPV6);
286 inq = &ip6intrq;
287 break;
288 #endif
289 default:
290 m_freem(m);
291 return;
294 s = splnet();
295 if (IF_QFULL(inq)) {
296 IF_DROP(inq);
297 m_freem(m);
298 } else
299 IF_ENQUEUE(inq, m);
300 splx(s);
304 * Handle packet from HIPPI that has no MAC header
307 #ifdef INET
308 void
309 hippi_ip_input(struct ifnet *ifp, struct mbuf *m)
311 struct ifqueue *inq;
312 int s;
314 schednetisr(NETISR_IP);
315 inq = &ipintrq;
317 s = splnet();
318 if (IF_QFULL(inq)) {
319 IF_DROP(inq);
320 m_freem(m);
321 } else
322 IF_ENQUEUE(inq, m);
323 splx(s);
325 #endif
328 * Perform common duties while attaching to interface list
330 void
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);
344 #if NBPFILTER > 0
345 bpfattach(ifp, DLT_HIPPI, sizeof(struct hippi_header));
346 #endif