1 | /* $NetBSD: if_atm.c,v 1.38 2016/04/28 00:16:56 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 | * IP <=> ATM address resolution. |
30 | */ |
31 | |
32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: if_atm.c,v 1.38 2016/04/28 00:16:56 ozaki-r Exp $" ); |
34 | |
35 | #ifdef _KERNEL_OPT |
36 | #include "opt_inet.h" |
37 | #include "opt_natm.h" |
38 | #endif |
39 | |
40 | #if defined(INET) || defined(INET6) |
41 | |
42 | #include <sys/param.h> |
43 | #include <sys/systm.h> |
44 | #include <sys/mbuf.h> |
45 | #include <sys/socket.h> |
46 | #include <sys/time.h> |
47 | #include <sys/kernel.h> |
48 | #include <sys/errno.h> |
49 | #include <sys/ioctl.h> |
50 | #include <sys/syslog.h> |
51 | #include <sys/proc.h> |
52 | |
53 | #include <net/if.h> |
54 | #include <net/if_dl.h> |
55 | #include <net/route.h> |
56 | #include <net/if_atm.h> |
57 | |
58 | #include <netinet/in.h> |
59 | #include <netinet/in_systm.h> |
60 | #include <netinet/in_var.h> |
61 | #include <netinet/ip.h> |
62 | #include <netinet/if_atm.h> |
63 | |
64 | #ifdef NATM |
65 | #include <netnatm/natm.h> |
66 | #endif |
67 | |
68 | |
69 | /* |
70 | * atm_rtrequest: handle ATM rt request (in support of generic code) |
71 | * inputs: "req" = request code |
72 | * "rt" = route entry |
73 | * "sa" = sockaddr |
74 | */ |
75 | |
76 | void |
77 | atm_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) |
78 | { |
79 | struct sockaddr *gate = rt->rt_gateway; |
80 | struct atm_pseudoioctl api; |
81 | #ifdef NATM |
82 | const struct sockaddr_in *sin; |
83 | struct natmpcb *npcb = NULL; |
84 | const struct atm_pseudohdr *aph; |
85 | #endif |
86 | const struct ifnet *ifp = rt->rt_ifp; |
87 | uint8_t namelen = strlen(ifp->if_xname); |
88 | uint8_t addrlen = ifp->if_addrlen; |
89 | |
90 | if (rt->rt_flags & RTF_GATEWAY) /* link level requests only */ |
91 | return; |
92 | |
93 | switch (req) { |
94 | |
95 | case RTM_ADD: |
96 | |
97 | /* |
98 | * route added by a command (e.g. ifconfig, route, arp...). |
99 | * |
100 | * first check to see if this is not a host route, in which |
101 | * case we are being called via "ifconfig" to set the address. |
102 | */ |
103 | |
104 | if ((rt->rt_flags & RTF_HOST) == 0) { |
105 | union { |
106 | struct sockaddr sa; |
107 | struct sockaddr_dl sdl; |
108 | struct sockaddr_storage ss; |
109 | } u; |
110 | |
111 | sockaddr_dl_init(&u.sdl, sizeof(u.ss), |
112 | ifp->if_index, ifp->if_type, |
113 | NULL, namelen, NULL, addrlen); |
114 | rt_setgate(rt, &u.sa); |
115 | gate = rt->rt_gateway; |
116 | break; |
117 | } |
118 | |
119 | if (gate->sa_family != AF_LINK || |
120 | gate->sa_len < sockaddr_dl_measure(namelen, addrlen)) { |
121 | log(LOG_DEBUG, "atm_rtrequest: bad gateway value\n" ); |
122 | break; |
123 | } |
124 | |
125 | #ifdef DIAGNOSTIC |
126 | if (rt->rt_ifp->if_ioctl == NULL) panic("atm null ioctl" ); |
127 | #endif |
128 | |
129 | #ifdef NATM |
130 | /* |
131 | * let native ATM know we are using this VCI/VPI |
132 | * (i.e. reserve it) |
133 | */ |
134 | sin = satocsin(rt_getkey(rt)); |
135 | if (sin->sin_family != AF_INET) |
136 | goto failed; |
137 | aph = (const struct atm_pseudohdr *)CLLADDR(satosdl(gate)); |
138 | npcb = npcb_add(NULL, rt->rt_ifp, ATM_PH_VCI(aph), |
139 | ATM_PH_VPI(aph)); |
140 | if (npcb == NULL) |
141 | goto failed; |
142 | npcb->npcb_flags |= NPCB_IP; |
143 | npcb->ipaddr.s_addr = sin->sin_addr.s_addr; |
144 | /* XXX: move npcb to llinfo when ATM ARP is ready */ |
145 | rt->rt_llinfo = (void *) npcb; |
146 | #endif |
147 | /* |
148 | * let the lower level know this circuit is active |
149 | */ |
150 | memcpy(&api.aph, CLLADDR(satocsdl(gate)), sizeof(api.aph)); |
151 | api.rxhand = NULL; |
152 | if (rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMENA, &api) != 0) { |
153 | printf("atm: couldn't add VC\n" ); |
154 | goto failed; |
155 | } |
156 | |
157 | satosdl(gate)->sdl_type = rt->rt_ifp->if_type; |
158 | satosdl(gate)->sdl_index = rt->rt_ifp->if_index; |
159 | |
160 | break; |
161 | |
162 | failed: |
163 | #ifdef NATM |
164 | if (npcb) { |
165 | npcb_free(npcb, NPCB_DESTROY); |
166 | rt->rt_llinfo = NULL; |
167 | } |
168 | #endif |
169 | rtrequest(RTM_DELETE, rt_getkey(rt), NULL, |
170 | rt_mask(rt), 0, NULL); |
171 | break; |
172 | |
173 | case RTM_DELETE: |
174 | |
175 | /* |
176 | * tell the lower layer to disable this circuit |
177 | */ |
178 | |
179 | memcpy(&api.aph, CLLADDR(satocsdl(gate)), sizeof(api.aph)); |
180 | api.rxhand = NULL; |
181 | (void)rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMDIS, &api); |
182 | |
183 | break; |
184 | } |
185 | } |
186 | |
187 | /* |
188 | * atmresolve: |
189 | * inputs: |
190 | * [1] "rt" = the link level route to use (or null if need to look one up) |
191 | * [2] "m" = mbuf containing the data to be sent |
192 | * [3] "dst" = sockaddr_in (IP) address of dest. |
193 | * output: |
194 | * [4] "desten" = ATM pseudo header which we will fill in VPI/VCI info |
195 | * return: |
196 | * 0 == resolve FAILED; note that "m" gets m_freem'd in this case |
197 | * 1 == resolve OK; desten contains result |
198 | * |
199 | * XXX: will need more work if we wish to support ATMARP in the kernel, |
200 | * but this is enough for PVCs entered via the "route" command. |
201 | */ |
202 | |
203 | int |
204 | atmresolve(const struct rtentry *rt0, struct mbuf *m, const struct sockaddr *dst, |
205 | struct atm_pseudohdr *desten /* OUT */) |
206 | { |
207 | const struct sockaddr_dl *sdl; |
208 | struct rtentry *rt = NULL; |
209 | |
210 | if (m->m_flags & (M_BCAST|M_MCAST)) { |
211 | log(LOG_INFO, "atmresolve: BCAST/MCAST packet detected/dumped\n" ); |
212 | goto bad; |
213 | } |
214 | |
215 | if (rt0 == NULL) { |
216 | rt = RTALLOC1(dst, 0); |
217 | if (rt == NULL) |
218 | goto bad; /* failed */ |
219 | if ((rt->rt_flags & RTF_GATEWAY) != 0 || |
220 | /* XXX: are we using LLINFO? */ |
221 | rt->rt_gateway->sa_family != AF_LINK) { |
222 | rtfree(rt); |
223 | goto bad; |
224 | } |
225 | } |
226 | |
227 | /* |
228 | * note that rt_gateway is a sockaddr_dl which contains the |
229 | * atm_pseudohdr data structure for this route. we currently |
230 | * don't need any rt_llinfo info (but will if we want to support |
231 | * ATM ARP [c.f. if_ether.c]). |
232 | */ |
233 | |
234 | sdl = satocsdl((rt ? rt : rt0)->rt_gateway); |
235 | |
236 | /* |
237 | * Check the address family and length is valid, the address |
238 | * is resolved; otherwise, try to resolve. |
239 | */ |
240 | |
241 | if (sdl->sdl_family == AF_LINK && sdl->sdl_alen == sizeof(*desten)) { |
242 | memcpy(desten, CLLADDR(sdl), sdl->sdl_alen); |
243 | if (rt != NULL) |
244 | rtfree(rt); |
245 | return (1); /* ok, go for it! */ |
246 | } |
247 | |
248 | if (rt != NULL) |
249 | rtfree(rt); |
250 | |
251 | /* |
252 | * we got an entry, but it doesn't have valid link address |
253 | * info in it (it is prob. the interface route, which has |
254 | * sdl_alen == 0). dump packet. (fall through to "bad"). |
255 | */ |
256 | |
257 | bad: |
258 | m_freem(m); |
259 | return (0); |
260 | } |
261 | #endif /* INET */ |
262 | |