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