| 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 | |