1 | /* $NetBSD: if_atmsubr.c,v 1.60 2016/10/03 11:06:06 ozaki-r Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1996 Charles D. Cranor and Washington University. |
5 | * 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 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | |
28 | /* |
29 | * if_atmsubr.c |
30 | */ |
31 | |
32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: if_atmsubr.c,v 1.60 2016/10/03 11:06:06 ozaki-r Exp $" ); |
34 | |
35 | #ifdef _KERNEL_OPT |
36 | #include "opt_inet.h" |
37 | #include "opt_gateway.h" |
38 | #include "opt_natm.h" |
39 | #endif |
40 | |
41 | #include <sys/param.h> |
42 | #include <sys/systm.h> |
43 | #include <sys/kernel.h> |
44 | #include <sys/malloc.h> |
45 | #include <sys/mbuf.h> |
46 | #include <sys/protosw.h> |
47 | #include <sys/socket.h> |
48 | #include <sys/ioctl.h> |
49 | #include <sys/errno.h> |
50 | #include <sys/syslog.h> |
51 | |
52 | #include <sys/cpu.h> |
53 | |
54 | #include <net/if.h> |
55 | #include <net/netisr.h> |
56 | #include <net/route.h> |
57 | #include <net/if_dl.h> |
58 | #include <net/if_types.h> |
59 | #include <net/if_atm.h> |
60 | #include <net/ethertypes.h> /* XXX: for ETHERTYPE_* */ |
61 | |
62 | #include <net/bpf.h> |
63 | |
64 | #include <netinet/in.h> |
65 | #include <netinet/if_atm.h> |
66 | |
67 | #if defined(INET) || defined(INET6) |
68 | #include <netinet/in_var.h> |
69 | #endif |
70 | #ifdef NATM |
71 | #include <netnatm/natm.h> |
72 | #endif |
73 | |
74 | #define senderr(e) { error = (e); goto bad;} |
75 | |
76 | /* |
77 | * atm_output: ATM output routine |
78 | * inputs: |
79 | * "ifp" = ATM interface to output to |
80 | * "m0" = the packet to output |
81 | * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI) |
82 | * "rt0" = the route to use |
83 | * returns: error code [0 == ok] |
84 | * |
85 | * note: special semantic: if (dst == NULL) then we assume "m" already |
86 | * has an atm_pseudohdr on it and just send it directly. |
87 | * [for native mode ATM output] if dst is null, then |
88 | * rt0 must also be NULL. |
89 | */ |
90 | |
91 | int |
92 | atm_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst, |
93 | const struct rtentry *rt) |
94 | { |
95 | uint16_t etype = 0; /* if using LLC/SNAP */ |
96 | int error = 0, sz; |
97 | struct atm_pseudohdr atmdst, *ad; |
98 | struct mbuf *m = m0; |
99 | struct atmllc *atmllc; |
100 | uint32_t atm_flags; |
101 | |
102 | if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) |
103 | senderr(ENETDOWN); |
104 | |
105 | /* |
106 | * If the queueing discipline needs packet classification, |
107 | * do it before prepending link headers. |
108 | */ |
109 | IFQ_CLASSIFY(&ifp->if_snd, m, |
110 | (dst != NULL ? dst->sa_family : AF_UNSPEC)); |
111 | |
112 | /* |
113 | * check for non-native ATM traffic (dst != NULL) |
114 | */ |
115 | if (dst) { |
116 | switch (dst->sa_family) { |
117 | #ifdef INET |
118 | case AF_INET: |
119 | #endif |
120 | #ifdef INET6 |
121 | case AF_INET6: |
122 | #endif |
123 | #if defined(INET) || defined(INET6) |
124 | if (dst->sa_family == AF_INET) |
125 | etype = ETHERTYPE_IP; |
126 | else |
127 | etype = ETHERTYPE_IPV6; |
128 | # ifdef ATM_PVCEXT |
129 | if (ifp->if_flags & IFF_POINTOPOINT) { |
130 | /* pvc subinterface */ |
131 | struct pvcsif *pvcsif = (struct pvcsif *)ifp; |
132 | atmdst = pvcsif->sif_aph; |
133 | break; |
134 | } |
135 | # endif |
136 | if (!atmresolve(rt, m, dst, &atmdst)) { |
137 | m = NULL; |
138 | /* XXX: atmresolve already free'd it */ |
139 | senderr(EHOSTUNREACH); |
140 | /* XXX: put ATMARP stuff here */ |
141 | /* XXX: watch who frees m on failure */ |
142 | } |
143 | break; |
144 | #endif |
145 | |
146 | case AF_UNSPEC: |
147 | /* |
148 | * XXX: bpfwrite or output from a pvc shadow if. |
149 | * assuming dst contains 12 bytes (atm pseudo |
150 | * header (4) + LLC/SNAP (8)) |
151 | */ |
152 | memcpy(&atmdst, dst->sa_data, sizeof(atmdst)); |
153 | break; |
154 | |
155 | default: |
156 | printf("%s: can't handle af%d\n" , ifp->if_xname, |
157 | dst->sa_family); |
158 | senderr(EAFNOSUPPORT); |
159 | } |
160 | |
161 | /* |
162 | * must add atm_pseudohdr to data |
163 | */ |
164 | sz = sizeof(atmdst); |
165 | atm_flags = ATM_PH_FLAGS(&atmdst); |
166 | if (atm_flags & ATM_PH_LLCSNAP) |
167 | sz += 8; /* sizeof snap == 8 */ |
168 | M_PREPEND(m, sz, M_DONTWAIT); |
169 | if (m == 0) |
170 | senderr(ENOBUFS); |
171 | ad = mtod(m, struct atm_pseudohdr *); |
172 | *ad = atmdst; |
173 | if (atm_flags & ATM_PH_LLCSNAP) { |
174 | atmllc = (struct atmllc *)(ad + 1); |
175 | memcpy(atmllc->llchdr, ATMLLC_HDR, |
176 | sizeof(atmllc->llchdr)); |
177 | ATM_LLC_SETTYPE(atmllc, etype); |
178 | } |
179 | } |
180 | |
181 | return ifq_enqueue(ifp, m); |
182 | |
183 | bad: |
184 | if (m) |
185 | m_freem(m); |
186 | return (error); |
187 | } |
188 | |
189 | /* |
190 | * Process a received ATM packet; |
191 | * the packet is in the mbuf chain m. |
192 | */ |
193 | void |
194 | atm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m, |
195 | void *rxhand) |
196 | { |
197 | pktqueue_t *pktq = NULL; |
198 | uint16_t etype = ETHERTYPE_IP; /* default */ |
199 | |
200 | if ((ifp->if_flags & IFF_UP) == 0) { |
201 | m_freem(m); |
202 | return; |
203 | } |
204 | ifp->if_ibytes += m->m_pkthdr.len; |
205 | |
206 | if (rxhand) { |
207 | #ifdef NATM |
208 | struct natmpcb *npcb = rxhand; |
209 | struct ifqueue *inq; |
210 | int s, isr = 0; |
211 | |
212 | s = splnet(); /* in case 2 atm cards @ diff lvls */ |
213 | npcb->npcb_inq++; /* count # in queue */ |
214 | splx(s); |
215 | isr = NETISR_NATM; |
216 | inq = &natmintrq; |
217 | m_set_rcvif(m, rxhand); /* XXX: overload */ |
218 | |
219 | IFQ_LOCK(inq); |
220 | if (IF_QFULL(inq)) { |
221 | IF_DROP(inq); |
222 | IFQ_UNLOCK(inq); |
223 | m_freem(m); |
224 | } else { |
225 | IF_ENQUEUE(inq, m); |
226 | IFQ_UNLOCK(inq); |
227 | schednetisr(isr); |
228 | } |
229 | #else |
230 | printf("%s: NATM detected but not configured in kernel\n" , |
231 | __func__); |
232 | m_freem(m); |
233 | #endif |
234 | return; |
235 | } |
236 | |
237 | /* |
238 | * handle LLC/SNAP header, if present |
239 | */ |
240 | if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) { |
241 | struct atmllc *alc; |
242 | if (m->m_len < sizeof(*alc) && |
243 | (m = m_pullup(m, sizeof(*alc))) == NULL) |
244 | return; /* failed */ |
245 | alc = mtod(m, struct atmllc *); |
246 | if (memcmp(alc, ATMLLC_HDR, 6)) { |
247 | printf( |
248 | "%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n" , |
249 | ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah)); |
250 | m_freem(m); |
251 | return; |
252 | } |
253 | etype = ATM_LLC_TYPE(alc); |
254 | m_adj(m, sizeof(*alc)); |
255 | } |
256 | |
257 | switch (etype) { |
258 | #ifdef INET |
259 | case ETHERTYPE_IP: |
260 | #if 0 /* XXX re-enable once atm_input runs in softint */ |
261 | if (ipflow_fastforward(m)) |
262 | return; |
263 | #endif |
264 | pktq = ip_pktq; |
265 | break; |
266 | #endif /* INET */ |
267 | #ifdef INET6 |
268 | case ETHERTYPE_IPV6: |
269 | #if 0 /* XXX re-enable once atm_input runs in softint */ |
270 | if (ip6flow_fastforward(&m)) |
271 | return; |
272 | #endif |
273 | pktq = ip6_pktq; |
274 | break; |
275 | #endif |
276 | default: |
277 | m_freem(m); |
278 | return; |
279 | } |
280 | |
281 | if (__predict_false(!pktq_enqueue(pktq, m, 0))) { |
282 | m_freem(m); |
283 | } |
284 | } |
285 | |
286 | /* |
287 | * Perform common duties while attaching to interface list |
288 | */ |
289 | void |
290 | atm_ifattach(struct ifnet *ifp) |
291 | { |
292 | |
293 | ifp->if_type = IFT_ATM; |
294 | ifp->if_addrlen = 0; |
295 | ifp->if_hdrlen = 0; |
296 | ifp->if_dlt = DLT_ATM_RFC1483; |
297 | ifp->if_mtu = ATMMTU; |
298 | ifp->if_output = atm_output; |
299 | #if 0 /* XXX XXX XXX */ |
300 | ifp->if_input = atm_input; |
301 | #endif |
302 | |
303 | if_alloc_sadl(ifp); |
304 | /* XXX Store LLADDR for ATMARP. */ |
305 | |
306 | bpf_attach(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc)); |
307 | } |
308 | |
309 | #ifdef ATM_PVCEXT |
310 | |
311 | static int pvc_max_number = 16; /* max number of PVCs */ |
312 | static int pvc_number = 0; /* pvc unit number */ |
313 | |
314 | struct ifnet * |
315 | pvcsif_alloc(void) |
316 | { |
317 | struct pvcsif *pvcsif; |
318 | |
319 | if (pvc_number >= pvc_max_number) |
320 | return NULL; |
321 | pvcsif = malloc(sizeof(struct pvcsif), |
322 | M_DEVBUF, M_WAITOK|M_ZERO); |
323 | if (pvcsif == NULL) |
324 | return NULL; |
325 | |
326 | snprintf(pvcsif->sif_if.if_xname, sizeof(pvcsif->sif_if.if_xname), |
327 | "pvc%d" , pvc_number++); |
328 | return (&pvcsif->sif_if); |
329 | } |
330 | #endif /* ATM_PVCEXT */ |
331 | |