| 1 | /*********************************************************** |
| 2 | Copyright IBM Corporation 1987 |
| 3 | |
| 4 | All Rights Reserved |
| 5 | |
| 6 | Permission to use, copy, modify, and distribute this software and its |
| 7 | documentation for any purpose and without fee is hereby granted, |
| 8 | provided that the above copyright notice appear in all copies and that |
| 9 | both that copyright notice and this permission notice appear in |
| 10 | supporting documentation, and that the name of IBM not be |
| 11 | used in advertising or publicity pertaining to distribution of the |
| 12 | software without specific, written prior permission. |
| 13 | |
| 14 | IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
| 15 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL |
| 16 | IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
| 17 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
| 18 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
| 19 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
| 20 | SOFTWARE. |
| 21 | |
| 22 | ******************************************************************/ |
| 23 | |
| 24 | /* |
| 25 | * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison |
| 26 | */ |
| 27 | /* $Header: clnp_arp.c,v 4.2 88/06/29 14:58:32 hagens Exp $ */ |
| 28 | /* $Source: /usr/argo/sys/netiso/RCS/clnp_arp.c,v $ */ |
| 29 | |
| 30 | #ifndef lint |
| 31 | static char *rcsid = "$Header: clnp_arp.c,v 4.2 88/06/29 14:58:32 hagens Exp $"; |
| 32 | #endif lint |
| 33 | |
| 34 | #ifdef ISO |
| 35 | |
| 36 | #include "types.h" |
| 37 | #include "param.h" |
| 38 | #include "mbuf.h" |
| 39 | #include "domain.h" |
| 40 | #include "protosw.h" |
| 41 | #include "socket.h" |
| 42 | #include "socketvar.h" |
| 43 | #include "errno.h" |
| 44 | #include "ioctl.h" |
| 45 | |
| 46 | #include "../net/if.h" |
| 47 | #include "../net/route.h" |
| 48 | |
| 49 | #include "iso.h" |
| 50 | #include "iso_var.h" |
| 51 | #include "iso_map.h" |
| 52 | #include "iso_snpac.h" |
| 53 | #include "clnp.h" |
| 54 | #include "clnp_stat.h" |
| 55 | #include "argo_debug.h" |
| 56 | |
| 57 | #define MAPTAB_BSIZ 20 /* bucket size */ |
| 58 | #define MAPTAB_NB 13 /* number of buckets */ |
| 59 | #define MAPTAB_SIZE (MAPTAB_BSIZ * MAPTAB_NB) |
| 60 | struct maptab iso_maptab[MAPTAB_SIZE]; |
| 61 | int iso_maptab_size = MAPTAB_SIZE; /* for isomap command */ |
| 62 | |
| 63 | #define MAPTAB_HASH(addr) \ |
| 64 | (((u_long) iso_hashchar(addr, addr->isoa_len)) % MAPTAB_NB) |
| 65 | |
| 66 | #define MAPTAB_LOOK(at,addr) { \ |
| 67 | register n; \ |
| 68 | at = &iso_maptab[MAPTAB_HASH(addr) * MAPTAB_BSIZ]; \ |
| 69 | for (n = 0 ; n < MAPTAB_BSIZ ; n++,at++) \ |
| 70 | if ((at->map_valid) && (iso_addrmatch1(&at->map_isoa, addr))) \ |
| 71 | break; \ |
| 72 | if (n >= MAPTAB_BSIZ) \ |
| 73 | at = 0; \ |
| 74 | } |
| 75 | |
| 76 | /* |
| 77 | * FUNCTION: clnp_arpresolve |
| 78 | * |
| 79 | * PURPOSE: Resolve a clnp address into hardware ethernet addr. |
| 80 | * |
| 81 | * RETURNS: 1 if addr is resolved |
| 82 | * 0 if addr is unknown |
| 83 | * |
| 84 | * SIDE EFFECTS: |
| 85 | * |
| 86 | * NOTES: This is a hack. If the address is local, then |
| 87 | * the packet is put on the loopback driver. Otherwise, |
| 88 | * if a translation is found, that ethernet address is |
| 89 | * returned. Otherwise, the packet is dropped. Thus, |
| 90 | * each translation must be placed (by hand) in the |
| 91 | * tables (see isomap(8)). |
| 92 | * TODO: should this map stuff be a critical section? |
| 93 | */ |
| 94 | clnp_arpresolve(ifp, m, dst, edst) |
| 95 | struct ifnet *ifp; /* outgoing interface */ |
| 96 | struct mbuf *m; /* pkt */ |
| 97 | struct sockaddr_iso *dst; /* destination */ |
| 98 | char *edst; /* RESULT: ethernet address */ |
| 99 | { |
| 100 | extern struct ifnet loif; /* loopback interface */ |
| 101 | struct maptab *at; /* ptr to map table entry */ |
| 102 | struct iso_addr *destiso; /* destination iso addr */ |
| 103 | |
| 104 | destiso = &dst->siso_addr; |
| 105 | |
| 106 | if (destiso->isoa_genaddr[0] == AFI_SNA) { |
| 107 | /* |
| 108 | * This is a subnetwork address. Return it immediately |
| 109 | */ |
| 110 | int sna_len; |
| 111 | |
| 112 | IFDEBUG(D_ESISOUTPUT) |
| 113 | printf("clnp_arpresolve: return SN address\n"); |
| 114 | ENDDEBUG |
| 115 | |
| 116 | sna_len = destiso->isoa_len - 1; /* subtract size of AFI */ |
| 117 | if (sna_len != 6) { |
| 118 | IFDEBUG(D_ESISOUTPUT) |
| 119 | printf("clnp_arpresolve: SN len is bad (%d)\n", sna_len); |
| 120 | ENDDEBUG |
| 121 | return(-1); |
| 122 | } |
| 123 | bcopy((caddr_t)&destiso->isoa_genaddr[1], (caddr_t)edst, sna_len); |
| 124 | return (1); |
| 125 | } |
| 126 | |
| 127 | IFDEBUG(D_ETHER) |
| 128 | printf("clnp_arpresolve: resolving %s\n", clnp_iso_addrp(destiso)); |
| 129 | ENDDEBUG |
| 130 | |
| 131 | /* if for us, use software loopback driver if up */ |
| 132 | if (clnp_ours(destiso)) { |
| 133 | IFDEBUG(D_ETHER) |
| 134 | printf("clnp_arpresolve: local destination\n"); |
| 135 | ENDDEBUG |
| 136 | if (loif.if_flags & IFF_UP) { |
| 137 | IFDEBUG(D_ETHER) |
| 138 | printf("clnp_arpresolve: calling looutput\n"); |
| 139 | ENDDEBUG |
| 140 | (void) looutput(&loif, m, (struct sockaddr *)dst); |
| 141 | /* |
| 142 | * The packet has already been sent and freed. |
| 143 | */ |
| 144 | return (0); |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | IFDEBUG(D_ETHER) |
| 149 | printf("clnp_arpresolve: NON-local destination\n"); |
| 150 | ENDDEBUG |
| 151 | |
| 152 | /* |
| 153 | * packet is not for us, check static map table for an entry |
| 154 | * This does not need to be a critical section because the |
| 155 | * table is not dynamically updated, except by a call to |
| 156 | * isomap(8) |
| 157 | */ |
| 158 | MAPTAB_LOOK(at, destiso); |
| 159 | if (at == 0) { /* not found */ |
| 160 | m_freem(m); |
| 161 | return (-1); |
| 162 | } else { |
| 163 | bcopy((caddr_t)at->map_enaddr, (caddr_t)edst, sizeof(at->map_enaddr)); |
| 164 | return (1); |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | /* |
| 169 | * FUNCTION: isomap_new |
| 170 | * |
| 171 | * PURPOSE: create a new entry in the iso address to ethernet |
| 172 | * address table |
| 173 | * |
| 174 | * RETURNS: pointer to newest entry, or NULL if none can be found |
| 175 | * |
| 176 | * SIDE EFFECTS: |
| 177 | * |
| 178 | * NOTES: TODO: timeout old entries |
| 179 | */ |
| 180 | struct maptab * |
| 181 | isomap_new(isoa) |
| 182 | struct iso_addr *isoa; /* iso address to enter into table */ |
| 183 | { |
| 184 | register struct maptab *at; |
| 185 | register int n; |
| 186 | |
| 187 | at = &iso_maptab[MAPTAB_HASH(isoa) * MAPTAB_BSIZ]; |
| 188 | for (n = 0 ; n < MAPTAB_BSIZ ; n++,at++) { |
| 189 | |
| 190 | IFDEBUG (D_IOCTL) |
| 191 | printf("isomap_new: at x%x ", at); |
| 192 | |
| 193 | if (at->map_valid) { |
| 194 | int i; |
| 195 | |
| 196 | printf("(valid) %s ", clnp_iso_addrp(&at->map_isoa)); |
| 197 | for (i=0; i<6; i++) |
| 198 | printf("%x%c", at->map_enaddr[i], i < 5 ? ':' : '\n'); |
| 199 | } else { |
| 200 | printf("invalid\n"); |
| 201 | } |
| 202 | ENDDEBUG |
| 203 | |
| 204 | if (!at->map_valid) /* found unused slot */ |
| 205 | return at; |
| 206 | } |
| 207 | return NULL; |
| 208 | } |
| 209 | |
| 210 | /* |
| 211 | * FUNCTION: isomap_free |
| 212 | * |
| 213 | * PURPOSE: free an entry in the iso address map table |
| 214 | * |
| 215 | * RETURNS: nothing |
| 216 | * |
| 217 | * SIDE EFFECTS: |
| 218 | * |
| 219 | * NOTES: |
| 220 | */ |
| 221 | isomap_free(at) |
| 222 | register struct maptab *at; /* entry to free */ |
| 223 | { |
| 224 | at->map_valid = 0; |
| 225 | } |
| 226 | |
| 227 | /* |
| 228 | * FUNCTION: isomap_ioctl |
| 229 | * |
| 230 | * PURPOSE: handle ioctls to change the iso address map |
| 231 | * |
| 232 | * RETURNS: unix error code |
| 233 | * |
| 234 | * SIDE EFFECTS: changes the maptab table declared above. |
| 235 | * |
| 236 | * NOTES: |
| 237 | */ |
| 238 | isomap_ioctl(cmd, data) |
| 239 | int cmd; /* ioctl to process */ |
| 240 | caddr_t data; /* data for the cmd */ |
| 241 | { |
| 242 | register struct arpreq_iso *ar = (struct arpreq_iso *)data; |
| 243 | register struct maptab *at; |
| 244 | register struct sockaddr_iso *siso; |
| 245 | register struct iso_addr *isoa; |
| 246 | |
| 247 | /* |
| 248 | * only process commands for the ISO address family |
| 249 | */ |
| 250 | if (ar->arp_pa.siso_family != AF_ISO) |
| 251 | return(EAFNOSUPPORT); |
| 252 | |
| 253 | /* look up this address in table */ |
| 254 | siso = (struct sockaddr_iso *)&ar->arp_pa; |
| 255 | isoa = &siso->siso_addr; |
| 256 | |
| 257 | IFDEBUG (D_IOCTL) |
| 258 | int i; |
| 259 | |
| 260 | printf("isomap_ioctl: "); |
| 261 | switch(cmd) { |
| 262 | case SIOCSISOMAP: printf("set"); break; |
| 263 | case SIOCDISOMAP: printf("delete"); break; |
| 264 | case SIOCGISOMAP: printf("get"); break; |
| 265 | } |
| 266 | printf(" %s to ", clnp_iso_addrp(isoa)); |
| 267 | for (i=0; i<6; i++) |
| 268 | printf("%x%c", ar->arp_ha.sa_data[i], i < 5 ? ':' : '\n'); |
| 269 | ENDDEBUG |
| 270 | |
| 271 | MAPTAB_LOOK(at, isoa); |
| 272 | if (at == NULL) { /* not found */ |
| 273 | if (cmd != SIOCSISOMAP) |
| 274 | return(ENXIO); |
| 275 | |
| 276 | /* TODO: what if setting and net is not directly attached */ |
| 277 | } |
| 278 | |
| 279 | switch(cmd) { |
| 280 | case SIOCSISOMAP: /* set entry */ |
| 281 | if (at == NULL) { |
| 282 | at = isomap_new(isoa); |
| 283 | if (at == NULL) |
| 284 | return(ENOBUFS); |
| 285 | } |
| 286 | bcopy((caddr_t)isoa, (caddr_t)&at->map_isoa, |
| 287 | sizeof (struct iso_addr)); |
| 288 | bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->map_enaddr, |
| 289 | sizeof(at->map_enaddr)); |
| 290 | at->map_valid++; |
| 291 | break; |
| 292 | |
| 293 | case SIOCDISOMAP: /* delete entry */ |
| 294 | isomap_free(at); |
| 295 | break; |
| 296 | |
| 297 | case SIOCGISOMAP: /* get entry */ |
| 298 | bcopy((caddr_t)at->map_enaddr, (caddr_t)ar->arp_ha.sa_data, |
| 299 | sizeof(at->map_enaddr)); |
| 300 | } |
| 301 | return(0); |
| 302 | } |
| 303 | #endif ISO |