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