1 /* $NetBSD: if_hippisubr.c,v 1.17 2003/08/07 16:32:53 agc 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.17 2003/08/07 16:32:53 agc 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 __P((struct ifnet *, struct mbuf *,
80 struct sockaddr *, struct rtentry *));
81 static void hippi_input __P((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(ifp, m0, dst, rt0)
92 struct ifnet *ifp;
93 struct mbuf *m0;
94 struct sockaddr *dst;
95 struct rtentry *rt0;
96 {
97 u_int16_t htype;
98 u_int32_t ifield = 0;
99 int s, len, error = 0;
100 struct mbuf *m = m0;
101 struct rtentry *rt;
102 struct hippi_header *hh;
103 u_int32_t *cci;
104 u_int32_t d2_len;
105 ALTQ_DECL(struct altq_pktattr pktattr;)
106
107 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
108 senderr(ENETDOWN);
109
110 /* HIPPI doesn't really do broadcast or multicast right now */
111 if (m->m_flags & (M_BCAST | M_MCAST))
112 senderr(EOPNOTSUPP); /* XXX: some other error? */
113
114 if ((rt = rt0) != NULL) {
115 if ((rt->rt_flags & RTF_UP) == 0) {
116 if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) {
117 rt->rt_refcnt--;
118 if (rt->rt_ifp != ifp)
119 return (*rt->rt_ifp->if_output)
120 (ifp, m0, dst, rt);
121 } else
122 senderr(EHOSTUNREACH);
123 }
124 if ((rt->rt_flags & RTF_GATEWAY) && dst->sa_family != AF_NS) {
125 if (rt->rt_gwroute == 0)
126 goto lookup;
127 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
128 rtfree(rt); rt = rt0;
129 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
130 if ((rt = rt->rt_gwroute) == 0)
131 senderr(EHOSTUNREACH);
132 /* the "G" test below also prevents rt == rt0 */
133 if ((rt->rt_flags & RTF_GATEWAY) ||
134 (rt->rt_ifp != ifp)) {
135 rt->rt_refcnt--;
136 rt0->rt_gwroute = 0;
137 senderr(EHOSTUNREACH);
138 }
139 }
140 }
141 if (rt->rt_flags & RTF_REJECT)
142 if (rt->rt_rmx.rmx_expire == 0 || /* XXX: no ARP */
143 time.tv_sec < rt->rt_rmx.rmx_expire)
144 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
145 }
146
147 /*
148 * If the queueing discipline needs packet classification,
149 * do it before prepending link headers.
150 */
151 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
152
153 switch (dst->sa_family) {
154 #ifdef INET
155 case AF_INET:
156 if (rt) {
157 struct sockaddr_dl *sdl =
158 (struct sockaddr_dl *) SDL(rt->rt_gateway);
159 if (sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0)
160 bcopy(LLADDR(sdl), &ifield, sizeof(ifield));
161 }
162 if (!ifield) /* XXX: bogus check, but helps us get going */
163 senderr(EHOSTUNREACH);
164 htype = htons(ETHERTYPE_IP);
165 break;
166 #endif
167
168 #ifdef INET6
169 case AF_INET6:
170 if (rt) {
171 struct sockaddr_dl *sdl =
172 (struct sockaddr_dl *) SDL(rt->rt_gateway);
173 if (sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0)
174 bcopy(LLADDR(sdl), &ifield, sizeof(ifield));
175 }
176 if (!ifield) /* XXX: bogus check, but helps us get going */
177 senderr(EHOSTUNREACH);
178 htype = htons(ETHERTYPE_IPV6);
179 break;
180 #endif
181
182 default:
183 printf("%s: can't handle af%d\n", ifp->if_xname,
184 dst->sa_family);
185 senderr(EAFNOSUPPORT);
186 }
187
188 if (htype != 0) {
189 struct llc *l;
190 M_PREPEND(m, sizeof (struct llc), M_DONTWAIT);
191 if (m == 0)
192 senderr(ENOBUFS);
193 l = mtod(m, struct llc *);
194 l->llc_control = LLC_UI;
195 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
196 l->llc_snap.org_code[0] = l->llc_snap.org_code[1] =
197 l->llc_snap.org_code[2] = 0;
198 bcopy((caddr_t) &htype, (caddr_t) &l->llc_snap.ether_type,
199 sizeof(u_int16_t));
200 }
201
202 d2_len = m->m_pkthdr.len;
203
204 /*
205 * Add local net header. If no space in first mbuf,
206 * allocate another.
207 */
208
209 M_PREPEND(m, sizeof (struct hippi_header) + 8, M_DONTWAIT);
210 if (m == 0)
211 senderr(ENOBUFS);
212 cci = mtod(m, u_int32_t *);
213 memset(cci, 0, sizeof(struct hippi_header) + 8);
214 cci[0] = 0;
215 cci[1] = ifield;
216 hh = (struct hippi_header *) &cci[2];
217 hh->hi_fp.fp_ulp = HIPPI_ULP_802;
218 hh->hi_fp.fp_flags = HIPPI_FP_D1_PRESENT;
219 hh->hi_fp.fp_offsets = htons(sizeof(struct hippi_le));
220 hh->hi_fp.fp_d2_len = htonl(d2_len);
221
222 /* Pad out the D2 area to end on a quadword (64-bit) boundry. */
223
224 if (d2_len % 8 != 0) {
225 static u_int32_t buffer[2] = {0, 0};
226 m_copyback(m, m->m_pkthdr.len, 8 - d2_len % 8, (caddr_t) buffer);
227 }
228
229 len = m->m_pkthdr.len;
230 s = splnet();
231 /*
232 * Queue message on interface, and start output if interface
233 * not yet active.
234 */
235 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
236 if (error) {
237 /* mbuf is already free */
238 splx(s);
239 return (error);
240 }
241 ifp->if_obytes += len;
242 if ((ifp->if_flags & IFF_OACTIVE) == 0)
243 (*ifp->if_start)(ifp);
244 splx(s);
245 return (error);
246
247 bad:
248 if (m)
249 m_freem(m);
250 return (error);
251 }
252
253 /*
254 * Process a received HIPPI packet;
255 * the packet is in the mbuf chain m with
256 * the HIPPI header.
257 */
258
259 static void
260 hippi_input(ifp, m)
261 struct ifnet *ifp;
262 struct mbuf *m;
263 {
264 struct ifqueue *inq;
265 struct llc *l;
266 u_int16_t htype;
267 struct hippi_header *hh;
268 int s;
269
270 if ((ifp->if_flags & IFF_UP) == 0) {
271 m_freem(m);
272 return;
273 }
274
275 /* XXX: need to check flags and drop if bogus! */
276
277 hh = mtod(m, struct hippi_header *);
278
279 ifp->if_ibytes += m->m_pkthdr.len;
280 if (hh->hi_le.le_dest_addr[0] & 1) {
281 if (bcmp((caddr_t)etherbroadcastaddr,
282 (caddr_t)hh->hi_le.le_dest_addr,
283 sizeof(etherbroadcastaddr)) == 0)
284 m->m_flags |= M_BCAST;
285 else
286 m->m_flags |= M_MCAST;
287 }
288 if (m->m_flags & (M_BCAST|M_MCAST))
289 ifp->if_imcasts++;
290
291 /* Skip past the HIPPI header. */
292 m_adj(m, sizeof(struct hippi_header));
293
294 l = mtod(m, struct llc *);
295 if (l->llc_dsap != LLC_SNAP_LSAP) {
296 m_freem(m);
297 return;
298 }
299 htype = ntohs(l->llc_snap.ether_type);
300 m_adj(m, 8);
301 switch (htype) {
302 #ifdef INET
303 case ETHERTYPE_IP:
304 schednetisr(NETISR_IP);
305 inq = &ipintrq;
306 break;
307 #endif
308 #ifdef INET6
309 case ETHERTYPE_IPV6:
310 schednetisr(NETISR_IPV6);
311 inq = &ip6intrq;
312 break;
313 #endif
314 default:
315 m_freem(m);
316 return;
317 }
318
319 s = splnet();
320 if (IF_QFULL(inq)) {
321 IF_DROP(inq);
322 m_freem(m);
323 } else
324 IF_ENQUEUE(inq, m);
325 splx(s);
326 }
327
328 /*
329 * Handle packet from HIPPI that has no MAC header
330 */
331
332 #ifdef INET
333 void
334 hippi_ip_input(ifp, m)
335 struct ifnet *ifp;
336 struct mbuf *m;
337 {
338 struct ifqueue *inq;
339 int s;
340
341 schednetisr(NETISR_IP);
342 inq = &ipintrq;
343
344 s = splnet();
345 if (IF_QFULL(inq)) {
346 IF_DROP(inq);
347 m_freem(m);
348 } else
349 IF_ENQUEUE(inq, m);
350 splx(s);
351 }
352 #endif
353
354 /*
355 * Perform common duties while attaching to interface list
356 */
357 void
358 hippi_ifattach(ifp, lla)
359 struct ifnet *ifp;
360 caddr_t lla;
361 {
362
363 ifp->if_type = IFT_HIPPI;
364 ifp->if_addrlen = 6; /* regular 802.3 MAC address */
365 ifp->if_hdrlen = sizeof(struct hippi_header) + 8; /* add CCI */
366 ifp->if_dlt = DLT_HIPPI;
367 ifp->if_mtu = HIPPIMTU;
368 ifp->if_output = hippi_output;
369 ifp->if_input = hippi_input;
370 ifp->if_baudrate = IF_Mbps(800); /* XXX double-check */
371
372 if_alloc_sadl(ifp);
373 memcpy(LLADDR(ifp->if_sadl), lla, ifp->if_addrlen);
374
375 #if NBPFILTER > 0
376 bpfattach(ifp, DLT_HIPPI, sizeof(struct hippi_header));
377 #endif
378 }
Cache object: 3d4785ee3d17e8b42d122e80bb920c6d
|