Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / netproto / atm / uni / uniarp_cache.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/netatm/uni/uniarp_cache.c,v 1.4 1999/08/28 00:49:02 peter Exp $
27  *
28  */
29
30 /*
31  * ATM Forum UNI Support
32  * ---------------------
33  *
34  * UNI ATMARP support (RFC1577) - ARP cache processing
35  *
36  */
37
38 #include <netatm/kern_include.h>
39
40 #include <netatm/ipatm/ipatm_var.h>
41 #include <netatm/ipatm/ipatm_serv.h>
42 #include <netatm/uni/unisig_var.h>
43 #include <netatm/uni/uniip_var.h>
44
45 #ifndef lint
46 __RCSID("@(#) $FreeBSD: src/sys/netatm/uni/uniarp_cache.c,v 1.4 1999/08/28 00:49:02 peter Exp $");
47 #endif
48
49
50 /*
51  * Add data to the arp table cache
52  * 
53  * Called at splnet.
54  *
55  * Arguments:
56  *      uip     pointer to UNI IP interface
57  *      ip      pointer to IP address structure
58  *      atm     pointer to ATM address structure
59  *      atmsub  pointer to ATM subaddress structure
60  *      origin  source of arp information
61  *
62  * Returns:
63  *      0       cache successfully updated
64  *      else    updated failed - reason indicated
65  *
66  */
67 int
68 uniarp_cache_svc(uip, ip, atm, atmsub, origin)
69         struct uniip            *uip;
70         struct in_addr          *ip;
71         Atm_addr                *atm;
72         Atm_addr                *atmsub;
73         u_int                   origin;
74 {
75         struct ip_nif           *inp;
76         struct ipvcc            *ivp, *inext, *itail;
77         struct uniarp           *nouap, *ipuap;
78         char                    abuf[64];
79
80 #ifdef DIAGNOSTIC
81         strncpy(abuf, unisig_addr_print(atmsub), sizeof(abuf));
82         abuf[sizeof(abuf) - 1] = 0;
83         ATM_DEBUG4("cache_svc: ip=%s, atm=(%s,%s), origin=%d\n",
84                 inet_ntoa(*ip), unisig_addr_print(atm), abuf, origin);
85 #endif
86
87         /*
88          * Get interface info
89          */
90         inp = uip->uip_ipnif;
91
92         /*
93          * Find both cached entry and 'nomap' entries for this data.
94          */
95         UNIARP_LOOKUP(ip->s_addr, ipuap);
96         for (nouap = uniarp_nomaptab; nouap; nouap = nouap->ua_next) {
97                 if (ATM_ADDR_EQUAL(atm, &nouap->ua_dstatm) &&
98                     ATM_ADDR_EQUAL(atmsub, &nouap->ua_dstatmsub) &&
99                     (nouap->ua_intf == uip))
100                         break;
101         }
102
103         /*
104          * If there aren't any entries yet, create one
105          */
106         if ((ipuap == NULL) && (nouap == NULL)) {
107                 ipuap = (struct uniarp *)atm_allocate(&uniarp_pool);
108                 if (ipuap == NULL)
109                         return (ENOMEM);
110                 ipuap->ua_dstip.s_addr = ip->s_addr;
111                 ipuap->ua_dstatm.address_format = T_ATM_ABSENT;
112                 ipuap->ua_dstatmsub.address_format = T_ATM_ABSENT;
113                 ipuap->ua_intf = uip;
114                 UNIARP_ADD(ipuap);
115         }
116
117         /*
118          * If there's no cached mapping, then make the 'nomap' entry
119          * the new cached entry.
120          */
121         if (ipuap == NULL) {
122                 UNLINK(nouap, struct uniarp, uniarp_nomaptab, ua_next);
123                 nouap->ua_dstip.s_addr = ip->s_addr;
124                 ipuap = nouap;
125                 nouap = NULL;
126                 UNIARP_ADD(ipuap);
127         }
128
129         /*
130          * We need to check the consistency of the new data with any 
131          * cached data.  So taking the easy case first, if there isn't
132          * an ATM address in the cache then we can skip all these checks.
133          */
134         if (ipuap->ua_dstatm.address_format != T_ATM_ABSENT) {
135                 /*
136                  * See if the new data conflicts with what's in the cache
137                  */
138                 if (ATM_ADDR_EQUAL(atm, &ipuap->ua_dstatm) &&
139                     ATM_ADDR_EQUAL(atmsub, &ipuap->ua_dstatmsub) &&
140                     (uip == ipuap->ua_intf)) {
141                         /*
142                          * No conflicts here
143                          */
144                         goto dataok;
145                 }
146
147                 /*
148                  * Data conflict...how we deal with this depends on
149                  * the origins of the conflicting data
150                  */
151                 if (origin == ipuap->ua_origin) {
152                         /*
153                          * The new data has equal precedence - if there are
154                          * any VCCs using this entry, then we reject this
155                          * "duplicate IP address" update.
156                          */
157                         if (ipuap->ua_ivp != NULL) {
158                                 strncpy(abuf, unisig_addr_print(atmsub),
159                                         sizeof(abuf));
160                                 abuf[sizeof(abuf) - 1] = 0;
161                                 log(LOG_WARNING, 
162                                         "uniarp: duplicate IP address %s from %s,%s\n",
163                                         inet_ntoa(*ip), unisig_addr_print(atm),
164                                         abuf);
165                                 return (EACCES);
166                         }
167
168                 } else if (origin > ipuap->ua_origin) {
169                         /*
170                          * New data's origin has higher precedence,
171                          * so accept the new mapping and notify IP/ATM
172                          * that a mapping change has occurred.  IP/ATM will
173                          * close any VCC's which aren't waiting for this map.
174                          */
175                         ipuap->ua_flags |= UAF_LOCKED;
176                         for (ivp = ipuap->ua_ivp; ivp; ivp = inext) {
177                                 inext = ivp->iv_arpnext;
178                                 (*inp->inf_arpnotify)(ivp, MAP_CHANGED);
179                         }
180                         ipuap->ua_flags &= ~UAF_LOCKED;
181                 } else {
182                         /*
183                          * New data is of lesser origin precedence,
184                          * so we just reject the update attempt.
185                          */
186                         return (EACCES);
187                 }
188
189                 strncpy(abuf, unisig_addr_print(atmsub), sizeof(abuf));
190                 abuf[sizeof(abuf) - 1] = 0;
191                 log(LOG_WARNING, 
192                         "uniarp: ATM address for %s changed to %s,%s\n",
193                         inet_ntoa(*ip), unisig_addr_print(atm), abuf);
194         }
195
196         /*
197          * Update the cache entry with the new data
198          */
199         ATM_ADDR_COPY(atm, &ipuap->ua_dstatm);
200         ATM_ADDR_COPY(atmsub, &ipuap->ua_dstatmsub);
201         ipuap->ua_intf = uip;
202
203 dataok:
204         /*
205          * Update cache data origin
206          */
207         ipuap->ua_origin = MAX(ipuap->ua_origin, origin);
208
209         /*
210          * Ok, now act on this new/updated cache data
211          */
212         ipuap->ua_flags |= UAF_LOCKED;
213
214         /*
215          * Save pointer to last VCC currently on cached entry chain that
216          * will need to be notified of the map becoming valid
217          */
218         itail = NULL;
219         if ((ipuap->ua_flags & UAF_VALID) == 0) {
220
221                 for (itail = ipuap->ua_ivp; itail && itail->iv_arpnext; 
222                                 itail = itail->iv_arpnext) {
223                 }
224         }
225
226         /*
227          * If there was a 'nomap' entry for this mapping, then we need to
228          * announce the new mapping to them first.
229          */
230         if (nouap) {
231                 
232                 /*
233                  * Move the VCCs from this entry to the cache entry and
234                  * let them know there's a valid mapping now
235                  */
236                 for (ivp = nouap->ua_ivp; ivp; ivp = inext) {
237                         inext = ivp->iv_arpnext;
238
239                         UNLINK(ivp, struct ipvcc, nouap->ua_ivp, iv_arpnext);
240
241                         LINK2TAIL(ivp, struct ipvcc, ipuap->ua_ivp, iv_arpnext);
242                         ivp->iv_arpent = (struct arpmap *)ipuap;
243
244                         (*inp->inf_arpnotify)(ivp, MAP_VALID);
245                 }
246
247                 /*
248                  * Unlink and free the 'nomap' entry
249                  */
250                 UNLINK(nouap, struct uniarp, uniarp_nomaptab, ua_next);
251                 UNIARP_CANCEL(nouap);
252                 atm_free((caddr_t)nouap);
253         }
254
255         /*
256          * Now, if this entry wasn't valid, notify the remaining VCCs
257          */
258         if (itail) {
259
260                 for (ivp = ipuap->ua_ivp; ivp; ivp = inext) {
261                         inext = ivp->iv_arpnext;
262                         (*inp->inf_arpnotify)(ivp, MAP_VALID);
263                         if (ivp == itail)
264                                 break;
265                 }
266         }
267         ipuap->ua_flags &= ~UAF_LOCKED;
268
269         /*
270          * We now have a valid cache entry, so cancel any retry timer
271          * and reset the aging timeout
272          */
273         UNIARP_CANCEL(ipuap);
274         if ((ipuap->ua_origin == UAO_REGISTER) && (origin != UAO_REGISTER)) {
275                 if (((ipuap->ua_flags & UAF_VALID) == 0) ||
276                     (ipuap->ua_aging <= 
277                                 UNIARP_SERVER_AGE - UNIARP_MIN_REFRESH)) {
278                         ipuap->ua_flags |= UAF_REFRESH;
279                         ipuap->ua_aging = UNIARP_SERVER_AGE;
280                         ipuap->ua_retry = UNIARP_SERVER_RETRY;
281                 }
282         } else {
283                 if (uip->uip_arpstate == UIAS_SERVER_ACTIVE) {
284                         ipuap->ua_aging = UNIARP_SERVER_AGE;
285                         ipuap->ua_retry = UNIARP_SERVER_RETRY;
286                 } else {
287                         ipuap->ua_aging = UNIARP_CLIENT_AGE;
288                         ipuap->ua_retry = UNIARP_CLIENT_RETRY;
289                 }
290                 ipuap->ua_flags |= UAF_REFRESH;
291         }
292         ipuap->ua_flags |= UAF_VALID;
293         ipuap->ua_flags &= ~UAF_USED;
294         return (0);
295 }
296
297
298 /*
299  * Process ARP data from a PVC
300  * 
301  * The arp table cache is never updated with PVC information.
302  * 
303  * Called at splnet.
304  *
305  * Arguments:
306  *      ivp     pointer to input PVC's IPVCC control block
307  *      ip      pointer to IP address structure
308  *      atm     pointer to ATM address structure
309  *      atmsub  pointer to ATM subaddress structure
310  *
311  * Returns:
312  *      none
313  *
314  */
315 void
316 uniarp_cache_pvc(ivp, ip, atm, atmsub)
317         struct ipvcc            *ivp;
318         struct in_addr          *ip;
319         Atm_addr                *atm;
320         Atm_addr                *atmsub;
321 {
322         struct ip_nif           *inp;
323         struct uniarp           *uap;
324
325 #ifdef DIAGNOSTIC
326         char    buf[64];
327         int     vpi = 0, vci = 0;
328
329         if ((ivp->iv_conn) && (ivp->iv_conn->co_connvc)) {
330                 vpi = ivp->iv_conn->co_connvc->cvc_vcc->vc_vpi;
331                 vci = ivp->iv_conn->co_connvc->cvc_vcc->vc_vci;
332         }
333         strncpy(buf, unisig_addr_print(atmsub), sizeof(buf));
334         buf[sizeof(buf) - 1] = 0;
335         ATM_DEBUG5("cache_pvc: vcc=(%d,%d), ip=%s, atm=(%s,%s)\n",
336                 vpi, vci, inet_ntoa(*ip), unisig_addr_print(atm), buf);
337 #endif
338
339         /*
340          * Get PVC info
341          */
342         inp = ivp->iv_ipnif;
343         uap = (struct uniarp *)ivp->iv_arpent;
344
345         /*
346          * See if IP address for PVC has changed
347          */
348         if (uap->ua_dstip.s_addr != ip->s_addr) {
349                 if (uap->ua_dstip.s_addr != 0)
350                         (*inp->inf_arpnotify)(ivp, MAP_CHANGED);
351                 uap->ua_dstip.s_addr = ip->s_addr;
352         }
353
354         /*
355          * Let IP/ATM know if address has become valid
356          */
357         if ((uap->ua_flags & UAF_VALID) == 0)
358                 (*inp->inf_arpnotify)(ivp, MAP_VALID);
359         uap->ua_flags |= UAF_VALID;
360         uap->ua_aging = UNIARP_CLIENT_AGE;
361         uap->ua_retry = UNIARP_CLIENT_RETRY;
362
363         /*
364          * Save ATM addresses just for debugging
365          */
366         ATM_ADDR_COPY(atm, &uap->ua_dstatm);
367         ATM_ADDR_COPY(atmsub, &uap->ua_dstatmsub);
368
369         return;
370 }
371
372
373 /*
374  * Validate IP address
375  * 
376  * Arguments:
377  *      uip     pointer to UNI IP interface
378  *      ip      pointer to IP address structure
379  *      origin  source of arp information
380  *
381  * Returns:
382  *      0       IP address is acceptable
383  *      else    invalid IP address
384  *
385  */
386 int
387 uniarp_validate_ip(uip, ip, origin)
388         struct uniip            *uip;
389         struct in_addr          *ip;
390         u_int                   origin;
391 {
392         struct uniarp_prf       *upp;
393         int     i;
394
395
396         /*
397          * Can't be multicast or broadcast address
398          */
399         if (IN_MULTICAST(ntohl(ip->s_addr)) ||
400 #if (defined(BSD) && (BSD >= 199306))
401             in_broadcast(*ip, &uip->uip_ipnif->inf_nif->nif_if))
402 #else
403             in_broadcast(*ip))
404 #endif
405                 return (1);
406
407         /*
408          * For ATMARP registration information (including SCSP data),
409          * the address must be allowed by the interface's prefix list.
410          */
411         if ((origin == UAO_REGISTER) || (origin == UAO_SCSP)) {
412                 for (i = uip->uip_nprefix, upp = uip->uip_prefix;
413                      i; i--, upp++) {
414                         if ((ip->s_addr & upp->upf_mask.s_addr) == 
415                                         upp->upf_addr.s_addr)
416                                 break;
417                 }
418                 if (i == 0)
419                         return (1);
420         }
421
422         return (0);
423 }
424