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