Deleted Added
full compact
1/* $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $ */
2
3/*
4 *
5 * Copyright (c) 1996 Charles D. Cranor and Washington University.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Charles D. Cranor and
19 * Washington University.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35/*
36 * if_atmsubr.c
37 */
38
39#include "opt_inet.h"
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/mbuf.h>
44#include <sys/socket.h>
45
46#include <net/if.h>
47#include <net/netisr.h>
48#include <net/route.h>
49#include <net/if_dl.h>
50#include <net/if_types.h>
51#include <net/if_atm.h>
52
53#include <netinet/in.h>
54#include <netinet/if_atm.h>
55#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */
56#ifdef INET
57#include <netinet/in_var.h>
58#endif
59#ifdef NATM
60#include <netnatm/natm.h>
61#endif
62
63#include "bpfilter.h"
64#if NBPFILTER > 0
65/*
66 * bpf support.
67 * the code is derived from if_loop.c.
68 * bpf support should belong to the driver but it's easier to implement
69 * it here since we can call bpf_mtap before atm_output adds a pseudo
70 * header to the mbuf.
71 * --kjc
72 */
73#include <net/bpf.h>
74#endif /* NBPFILTER > 0 */
75
76#define senderr(e) { error = (e); goto bad;}
77
78/*
79 * atm_output: ATM output routine
80 * inputs:
81 * "ifp" = ATM interface to output to
82 * "m0" = the packet to output
83 * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI)
84 * "rt0" = the route to use
85 * returns: error code [0 == ok]
86 *
87 * note: special semantic: if (dst == NULL) then we assume "m" already
88 * has an atm_pseudohdr on it and just send it directly.
89 * [for native mode ATM output] if dst is null, then
90 * rt0 must also be NULL.
91 */
92
93int
94atm_output(ifp, m0, dst, rt0)
95 register struct ifnet *ifp;
96 struct mbuf *m0;
97 struct sockaddr *dst;
98 struct rtentry *rt0;
99{
100 u_int16_t etype = 0; /* if using LLC/SNAP */
101 int s, error = 0, sz;
102 struct atm_pseudohdr atmdst, *ad;
103 register struct mbuf *m = m0;
104 register struct rtentry *rt;
105 struct atmllc *atmllc;
106 u_int32_t atm_flags;
107
108 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
109 senderr(ENETDOWN);
110 gettime(&ifp->if_lastchange);
111
112 /*
113 * check route
114 */
115 if ((rt = rt0) != NULL) {
116
117 if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */
118 if ((rt0 = rt = RTALLOC1(dst, 0)) != NULL)
119 rt->rt_refcnt--;
120 else
121 senderr(EHOSTUNREACH);
122 }
123
124 if (rt->rt_flags & RTF_GATEWAY) {
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, 0);
130 if ((rt = rt->rt_gwroute) == 0)
131 senderr(EHOSTUNREACH);
132 }
133 }
134
135 /* XXX: put RTF_REJECT code here if doing ATMARP */
136
137 }
138
139 /*
140 * check for non-native ATM traffic (dst != NULL)
141 */
142 if (dst) {
143 switch (dst->sa_family) {
144#ifdef INET
145 case AF_INET:
146 if (!atmresolve(rt, m, dst, &atmdst)) {
147 m = NULL;
148 /* XXX: atmresolve already free'd it */
149 senderr(EHOSTUNREACH);
150 /* XXX: put ATMARP stuff here */
151 /* XXX: watch who frees m on failure */
152 }
153 etype = htons(ETHERTYPE_IP);
154 break;
155#endif
156
157 default:
158#if defined(__NetBSD__) || defined(__OpenBSD__)
159 printf("%s: can't handle af%d\n", ifp->if_xname,
160 dst->sa_family);
161#elif defined(__FreeBSD__) || defined(__bsdi__)
162 printf("%s%d: can't handle af%d\n", ifp->if_name,
163 ifp->if_unit, dst->sa_family);
164#endif
165 senderr(EAFNOSUPPORT);
166 }
167
168#if NBPFILTER > 0
169 /* BPF write needs to be handled specially */
170 if (dst && dst->sa_family == AF_UNSPEC) {
171 dst->sa_family = *(mtod(m, int *));
172 m->m_len -= sizeof(int);
173 m->m_pkthdr.len -= sizeof(int);
174 m->m_data += sizeof(int);
175 }
176
177 if (ifp->if_bpf) {
178 /*
179 * We need to prepend the address family as
180 * a four byte field. Cons up a dummy header
181 * to pacify bpf. This is safe because bpf
182 * will only read from the mbuf (i.e., it won't
183 * try to free it or keep a pointer a to it).
184 */
185 struct mbuf m1;
186 u_int af = dst->sa_family;
187
188 m1.m_next = m;
189 m1.m_len = 4;
190 m1.m_data = (char *)&af;
191
192 s = splimp();
193#if defined(__NetBSD__) || defined(__OpenBSD__)
194 bpf_mtap(&ifp->if_bpf, &m0);
195#elif defined(__FreeBSD__)
196 bpf_mtap(ifp, &m1);
197#endif
198 splx(s);
199 }
200#endif /* NBPFILTER > 0 */
201
202 /*
203 * must add atm_pseudohdr to data
204 */
205 sz = sizeof(atmdst);
206 atm_flags = ATM_PH_FLAGS(&atmdst);
207 if (atm_flags & ATM_PH_LLCSNAP) sz += 8; /* sizeof snap == 8 */
208 M_PREPEND(m, sz, M_DONTWAIT);
209 if (m == 0)
210 senderr(ENOBUFS);
211 ad = mtod(m, struct atm_pseudohdr *);
212 *ad = atmdst;
213 if (atm_flags & ATM_PH_LLCSNAP) {
214 atmllc = (struct atmllc *)(ad + 1);
215 bcopy(ATMLLC_HDR, atmllc->llchdr,
216 sizeof(atmllc->llchdr));
217 ATM_LLC_SETTYPE(atmllc, etype);
218 /* note: already in network order */
219 }
220 }
221
222 /*
223 * Queue message on interface, and start output if interface
224 * not yet active.
225 */
226
227 s = splimp();
228 if (IF_QFULL(&ifp->if_snd)) {
229 IF_DROP(&ifp->if_snd);
230 splx(s);
231 senderr(ENOBUFS);
232 }
233 ifp->if_obytes += m->m_pkthdr.len;
234 IF_ENQUEUE(&ifp->if_snd, m);
235 if ((ifp->if_flags & IFF_OACTIVE) == 0)
236 (*ifp->if_start)(ifp);
237 splx(s);
238 return (error);
239
240bad:
241 if (m)
242 m_freem(m);
243 return (error);
244}
245
246/*
247 * Process a received ATM packet;
248 * the packet is in the mbuf chain m.
249 */
250void
251atm_input(ifp, ah, m, rxhand)
252 struct ifnet *ifp;
253 register struct atm_pseudohdr *ah;
254 struct mbuf *m;
255 void *rxhand;
256{
257 register struct ifqueue *inq;
258 u_int16_t etype = ETHERTYPE_IP; /* default */
259 int s;
260
261 if ((ifp->if_flags & IFF_UP) == 0) {
262 m_freem(m);
263 return;
264 }
265 gettime(&ifp->if_lastchange);
266 ifp->if_ibytes += m->m_pkthdr.len;
267
268#if NBPFILTER > 0
269 if (ifp->if_bpf) {
270 /*
271 * We need to prepend the address family as
272 * a four byte field. Cons up a dummy header
273 * to pacify bpf. This is safe because bpf
274 * will only read from the mbuf (i.e., it won't
275 * try to free it or keep a pointer to it).
276 */
277 struct mbuf m0;
278 u_int af = AF_INET;
279
280 m0.m_next = m;
281 m0.m_len = 4;
282 m0.m_data = (char *)&af;
283
284#if defined(__NetBSD__) || defined(__OpenBSD__)
285 bpf_mtap(&ifp->if_bpf, &m0);
286#elif defined(__FreeBSD__)
287 bpf_mtap(ifp, &m0);
288#endif
289 }
290#endif /* NBPFILTER > 0 */
291
292 if (rxhand) {
293#ifdef NATM
294 struct natmpcb *npcb = rxhand;
295 s = splimp(); /* in case 2 atm cards @ diff lvls */
296 npcb->npcb_inq++; /* count # in queue */
297 splx(s);
298 schednetisr(NETISR_NATM);
299 inq = &natmintrq;
300 m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
301#else
302 printf("atm_input: NATM detected but not configured in kernel\n");
303 m_freem(m);
304 return;
305#endif
306 } else {
307 /*
308 * handle LLC/SNAP header, if present
309 */
310 if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
311 struct atmllc *alc;
312 if (m->m_len < sizeof(*alc) && (m = m_pullup(m, sizeof(*alc))) == 0)
313 return; /* failed */
314 alc = mtod(m, struct atmllc *);
315 if (bcmp(alc, ATMLLC_HDR, 6)) {
316#if defined(__NetBSD__) || defined(__OpenBSD__)
317 printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
318 ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
319#elif defined(__FreeBSD__) || defined(__bsdi__)
320 printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
321 ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
322#endif
323 m_freem(m);
324 return;
325 }
326 etype = ATM_LLC_TYPE(alc);
327 m_adj(m, sizeof(*alc));
328 }
329
330 switch (etype) {
331#ifdef INET
332 case ETHERTYPE_IP:
333 schednetisr(NETISR_IP);
334 inq = &ipintrq;
335 break;
336#endif
337 default:
338 m_freem(m);
339 return;
340 }
341 }
342
343 s = splimp();
344 if (IF_QFULL(inq)) {
345 IF_DROP(inq);
346 m_freem(m);
347 } else
348 IF_ENQUEUE(inq, m);
349 splx(s);
350}
351
352/*
353 * Perform common duties while attaching to interface list
354 */
355void
356atm_ifattach(ifp)
357 register struct ifnet *ifp;
358{
359 register struct ifaddr *ifa;
360 register struct sockaddr_dl *sdl;
361
362 ifp->if_type = IFT_ATM;
363 ifp->if_addrlen = 0;
364 ifp->if_hdrlen = 0;
365 ifp->if_mtu = ATMMTU;
366 ifp->if_output = atm_output;
367
368#if defined(__NetBSD__) || defined(__OpenBSD__)
369 for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
370 ifa = ifa->ifa_list.tqe_next)
371#elif defined(__FreeBSD__) && ((__FreeBSD__ > 2) || defined(_NET_IF_VAR_H_))
372/*
373 * for FreeBSD-3.0. 3.0-SNAP-970124 still sets -D__FreeBSD__=2!
374 * XXX -- for now, use newly-introduced "net/if_var.h" as an identifier.
375 * need a better way to identify 3.0. -- kjc
376 */
377 for (ifa = ifp->if_addrhead.tqh_first; ifa;
378 ifa = ifa->ifa_link.tqe_next)
379#elif defined(__FreeBSD__) || defined(__bsdi__)
380 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
381#endif
382
383 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
384 sdl->sdl_family == AF_LINK) {
385 sdl->sdl_type = IFT_ATM;
386 sdl->sdl_alen = ifp->if_addrlen;
387#ifdef notyet /* if using ATMARP, store hardware address using the next line */
388 bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen);
389#endif
390 break;
391 }
392#if NBPFILTER > 0
393#if defined(__NetBSD__) || defined(__OpenBSD__)
394 bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
395#elif defined(__FreeBSD__)
396 bpfattach(ifp, DLT_NULL, sizeof(u_int));
397#endif
398#endif /* NBPFILTER > 0 */
399}