1 /* $NetBSD: if_hippisubr.c,v 1.25 2006/11/16 01:33:40 christos Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
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.
18 *
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.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: if_hippisubr.c,v 1.25 2006/11/16 01:33:40 christos Exp $");
34
35 #include "opt_inet.h"
36
37 #include "bpfilter.h"
38
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>
49
50 #include <machine/cpu.h>
51
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>
58
59 #if NBPFILTER > 0
60 #include <net/bpf.h>
61 #endif
62
63 #include <net/if_hippi.h>
64
65 #include <netinet/in.h>
66 #if defined(INET) || defined(INET6)
67 #include <netinet/in_var.h>
68 #endif
69
70 #define senderr(e) { error = (e); goto bad;}
71
72 #define SIN(x) ((struct sockaddr_in *)x)
73 #define SDL(x) ((struct sockaddr_dl *)x)
74
75 #ifndef llc_snap
76 #define llc_snap llc_un.type_snap
77 #endif
78
79 static int hippi_output(struct ifnet *, struct mbuf *,
80 struct sockaddr *, struct rtentry *);
81 static void hippi_input(struct ifnet *, struct mbuf *);
82
83 /*
84 * HIPPI output routine.
85 * Encapsulate a packet of type family for the local net.
86 * I don't know anything about the mapping of AppleTalk or OSI
87 * protocols to HIPPI, so I don't include any code for them.
88 */
89
90 static int
91 hippi_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
92 struct rtentry *rt0)
93 {
94 u_int16_t htype;
95 u_int32_t ifield = 0;
96 int error = 0;
97 struct mbuf *m = m0;
98 struct rtentry *rt;
99 struct hippi_header *hh;
100 u_int32_t *cci;
101 u_int32_t d2_len;
102 ALTQ_DECL(struct altq_pktattr pktattr;)
103
104 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
105 senderr(ENETDOWN);
106
107 /* HIPPI doesn't really do broadcast or multicast right now */
108 if (m->m_flags & (M_BCAST | M_MCAST))
109 senderr(EOPNOTSUPP); /* XXX: some other error? */
110
111 if ((rt = rt0) != NULL) {
112 if ((rt->rt_flags & RTF_UP) == 0) {
113 if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) {
114 rt->rt_refcnt--;
115 if (rt->rt_ifp != ifp)
116 return (*rt->rt_ifp->if_output)
117 (ifp, m0, dst, rt);
118 } else
119 senderr(EHOSTUNREACH);
120 }
121 if ((rt->rt_flags & RTF_GATEWAY) && dst->sa_family != AF_NS) {
122 if (rt->rt_gwroute == 0)
123 goto lookup;
124 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
125 rtfree(rt); rt = rt0;
126 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
127 if ((rt = rt->rt_gwroute) == 0)
128 senderr(EHOSTUNREACH);
129 /* the "G" test below also prevents rt == rt0 */
130 if ((rt->rt_flags & RTF_GATEWAY) ||
131 (rt->rt_ifp != ifp)) {
132 rt->rt_refcnt--;
133 rt0->rt_gwroute = 0;
134 senderr(EHOSTUNREACH);
135 }
136 }
137 }
138 if (rt->rt_flags & RTF_REJECT)
139 if (rt->rt_rmx.rmx_expire == 0 || /* XXX: no ARP */
140 time_second < rt->rt_rmx.rmx_expire)
141 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
142 }
143
144 /*
145 * If the queueing discipline needs packet classification,
146 * do it before prepending link headers.
147 */
148 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
149
150 switch (dst->sa_family) {
151 #ifdef INET
152 case AF_INET:
153 if (rt) {
154 struct sockaddr_dl *sdl =
155 (struct sockaddr_dl *) SDL(rt->rt_gateway);
156 if (sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0)
157 bcopy(LLADDR(sdl), &ifield, sizeof(ifield));
158 }
159 if (!ifield) /* XXX: bogus check, but helps us get going */
160 senderr(EHOSTUNREACH);
161 htype = htons(ETHERTYPE_IP);
162 break;
163 #endif
164
165 #ifdef INET6
166 case AF_INET6:
167 if (rt) {
168 struct sockaddr_dl *sdl =
169 (struct sockaddr_dl *) SDL(rt->rt_gateway);
170 if (sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0)
171 bcopy(LLADDR(sdl), &ifield, sizeof(ifield));
172 }
173 if (!ifield) /* XXX: bogus check, but helps us get going */
174 senderr(EHOSTUNREACH);
175 htype = htons(ETHERTYPE_IPV6);
176 break;
177 #endif
178
179 default:
180 printf("%s: can't handle af%d\n", ifp->if_xname,
181 dst->sa_family);
182 senderr(EAFNOSUPPORT);
183 }
184
185 if (htype != 0) {
186 struct llc *l;
187 M_PREPEND(m, sizeof (struct llc), M_DONTWAIT);
188 if (m == 0)
189 senderr(ENOBUFS);
190 l = mtod(m, struct llc *);
191 l->llc_control = LLC_UI;
192 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
193 l->llc_snap.org_code[0] = l->llc_snap.org_code[1] =
194 l->llc_snap.org_code[2] = 0;
195 bcopy((caddr_t) &htype, (caddr_t) &l->llc_snap.ether_type,
196 sizeof(u_int16_t));
197 }
198
199 d2_len = m->m_pkthdr.len;
200
201 /*
202 * Add local net header. If no space in first mbuf,
203 * allocate another.
204 */
205
206 M_PREPEND(m, sizeof (struct hippi_header) + 8, M_DONTWAIT);
207 if (m == 0)
208 senderr(ENOBUFS);
209 cci = mtod(m, u_int32_t *);
210 memset(cci, 0, sizeof(struct hippi_header) + 8);
211 cci[0] = 0;
212 cci[1] = ifield;
213 hh = (struct hippi_header *) &cci[2];
214 hh->hi_fp.fp_ulp = HIPPI_ULP_802;
215 hh->hi_fp.fp_flags = HIPPI_FP_D1_PRESENT;
216 hh->hi_fp.fp_offsets = htons(sizeof(struct hippi_le));
217 hh->hi_fp.fp_d2_len = htonl(d2_len);
218
219 /* Pad out the D2 area to end on a quadword (64-bit) boundry. */
220
221 if (d2_len % 8 != 0) {
222 static u_int32_t buffer[2] = {0, 0};
223 m_copyback(m, m->m_pkthdr.len, 8 - d2_len % 8, (caddr_t) buffer);
224 }
225
226 return ifq_enqueue(ifp, m ALTQ_COMMA ALTQ_DECL(&pktattr));
227
228 bad:
229 if (m)
230 m_freem(m);
231 return (error);
232 }
233
234 /*
235 * Process a received HIPPI packet;
236 * the packet is in the mbuf chain m with
237 * the HIPPI header.
238 */
239
240 static void
241 hippi_input(struct ifnet *ifp, struct mbuf *m)
242 {
243 struct ifqueue *inq;
244 struct llc *l;
245 u_int16_t htype;
246 struct hippi_header *hh;
247 int s;
248
249 if ((ifp->if_flags & IFF_UP) == 0) {
250 m_freem(m);
251 return;
252 }
253
254 /* XXX: need to check flags and drop if bogus! */
255
256 hh = mtod(m, struct hippi_header *);
257
258 ifp->if_ibytes += m->m_pkthdr.len;
259 if (hh->hi_le.le_dest_addr[0] & 1) {
260 if (memcmp(etherbroadcastaddr, hh->hi_le.le_dest_addr,
261 sizeof(etherbroadcastaddr)) == 0)
262 m->m_flags |= M_BCAST;
263 else
264 m->m_flags |= M_MCAST;
265 }
266 if (m->m_flags & (M_BCAST|M_MCAST))
267 ifp->if_imcasts++;
268
269 /* Skip past the HIPPI header. */
270 m_adj(m, sizeof(struct hippi_header));
271
272 l = mtod(m, struct llc *);
273 if (l->llc_dsap != LLC_SNAP_LSAP) {
274 m_freem(m);
275 return;
276 }
277 htype = ntohs(l->llc_snap.ether_type);
278 m_adj(m, 8);
279 switch (htype) {
280 #ifdef INET
281 case ETHERTYPE_IP:
282 schednetisr(NETISR_IP);
283 inq = &ipintrq;
284 break;
285 #endif
286 #ifdef INET6
287 case ETHERTYPE_IPV6:
288 schednetisr(NETISR_IPV6);
289 inq = &ip6intrq;
290 break;
291 #endif
292 default:
293 m_freem(m);
294 return;
295 }
296
297 s = splnet();
298 if (IF_QFULL(inq)) {
299 IF_DROP(inq);
300 m_freem(m);
301 } else
302 IF_ENQUEUE(inq, m);
303 splx(s);
304 }
305
306 /*
307 * Handle packet from HIPPI that has no MAC header
308 */
309
310 #ifdef INET
311 void
312 hippi_ip_input(struct ifnet *ifp, struct mbuf *m)
313 {
314 struct ifqueue *inq;
315 int s;
316
317 schednetisr(NETISR_IP);
318 inq = &ipintrq;
319
320 s = splnet();
321 if (IF_QFULL(inq)) {
322 IF_DROP(inq);
323 m_freem(m);
324 } else
325 IF_ENQUEUE(inq, m);
326 splx(s);
327 }
328 #endif
329
330 /*
331 * Perform common duties while attaching to interface list
332 */
333 void
334 hippi_ifattach(struct ifnet *ifp, caddr_t lla)
335 {
336
337 ifp->if_type = IFT_HIPPI;
338 ifp->if_addrlen = 6; /* regular 802.3 MAC address */
339 ifp->if_hdrlen = sizeof(struct hippi_header) + 8; /* add CCI */
340 ifp->if_dlt = DLT_HIPPI;
341 ifp->if_mtu = HIPPIMTU;
342 ifp->if_output = hippi_output;
343 ifp->if_input = hippi_input;
344 ifp->if_baudrate = IF_Mbps(800); /* XXX double-check */
345
346 if_alloc_sadl(ifp);
347 memcpy(LLADDR(ifp->if_sadl), lla, ifp->if_addrlen);
348
349 #if NBPFILTER > 0
350 bpfattach(ifp, DLT_HIPPI, sizeof(struct hippi_header));
351 #endif
352 }
Cache object: 0bc38282dd4ce4a97e272c830905c888
|