* Remove (void) casts for discarded return values.
[dragonfly.git] / sys / netproto / atm / uni / uniarp_vcm.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_vcm.c,v 1.5 2000/01/17 20:49:55 mks Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/uni/uniarp_vcm.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) - Virtual Channel Management
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 "uniip_var.h"
43
44 /*
45  * Local variables
46  */
47 static struct attr_llc  uniarp_llc = {
48         T_ATM_PRESENT,
49         {
50                 T_ATM_LLC_SHARING,
51                 8,
52                 {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06}
53         }
54 };
55
56 static struct t_atm_cause       uniarp_cause = {
57         T_ATM_ITU_CODING,
58         T_ATM_LOC_USER,
59         T_ATM_CAUSE_TEMPORARY_FAILURE,
60         {0, 0, 0, 0}
61 };
62
63
64 /*
65  * Process a new PVC requiring ATMARP support
66  * 
67  * This function is called after IP/ATM has successfully opened a PVC which
68  * requires ATMARP support.  We will send an InATMARP request over the PVC
69  * to elicit a response from the PVC's ATMARP peer informing us of its
70  * network address.  This information will also be used by IP/ATM in order 
71  * to complete its address-to-VC mapping table.
72  *
73  * Arguments:
74  *      ivp     pointer to PVC's IPVCC control block
75  *
76  * Returns:
77  *      MAP_PROCEEDING  - OK so far, querying for peer's mapping
78  *      MAP_FAILED      - error, unable to allocate resources
79  *
80  */
81 int
82 uniarp_pvcopen(struct ipvcc *ivp)
83 {
84         struct uniip    *uip;
85         struct uniarp   *uap;
86         int             err;
87
88         ATM_DEBUG1("uniarp_pvcopen: ivp=%p\n", ivp);
89
90         ivp->iv_arpent = NULL;
91
92         /*
93          * Check things out
94          */
95         if ((ivp->iv_flags & IVF_LLC) == 0)
96                 return (MAP_FAILED);
97
98         /*
99          * Get uni interface
100          */
101         uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
102         if (uip == NULL)
103                 return (MAP_FAILED);
104
105         /*
106          * Get an arp map entry
107          */
108         uap = (struct uniarp *)atm_allocate(&uniarp_pool);
109         if (uap == NULL)
110                 return (MAP_FAILED);
111
112         /*
113          * Create our CM connection
114          */
115         err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc,
116                         ivp->iv_conn, &ivp->iv_arpconn);
117         if (err) {
118                 /*
119                  * We don't take no (or maybe) for an answer
120                  */
121                 if (ivp->iv_arpconn) {
122                         atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
123                         ivp->iv_arpconn = NULL;
124                 }
125                 atm_free((caddr_t)uap);
126                 return (MAP_FAILED);
127         }
128
129         /*
130          * Get map entry set up
131          */
132         crit_enter();
133         uap->ua_dstatm.address_format = T_ATM_ABSENT;
134         uap->ua_dstatmsub.address_format = T_ATM_ABSENT;
135         uap->ua_intf = uip;
136
137         /*
138          * Put ivp on arp entry chain
139          */
140         LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
141         ivp->iv_arpent = (struct arpmap *)uap;
142
143         /*
144          * Put arp entry on pvc chain
145          */
146         LINK2TAIL(uap, struct uniarp, uniarp_pvctab, ua_next);
147
148         /*
149          * Send Inverse ATMARP request
150          */
151         uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp);
152
153         /*
154          * Start resend timer 
155          */
156         uap->ua_aging = UNIARP_REVALID_AGE;
157
158         crit_exit();
159         return (MAP_PROCEEDING);
160 }
161
162
163 /*
164  * Process a new outgoing SVC requiring ATMARP support
165  * 
166  * This function is called by the IP/ATM module to resolve a destination 
167  * IP address to an ATM address in order to open an SVC to that destination.
168  * If a valid mapping is already in our cache, then we just tell the caller
169  * about it and that's that.  Otherwise, we have to allocate a new arp entry
170  * and issue a query for the mapping.
171  *
172  * Arguments:
173  *      ivp     pointer to SVC's IPVCC control block
174  *      dst     pointer to destination IP address
175  *
176  * Returns:
177  *      MAP_VALID       - Got the answer, returned via iv_arpent field.
178  *      MAP_PROCEEDING  - OK so far, querying for peer's mapping
179  *      MAP_FAILED      - error, unable to allocate resources
180  *
181  */
182 int
183 uniarp_svcout(struct ipvcc *ivp, struct in_addr *dst)
184 {
185         struct uniip    *uip;
186         struct uniarp   *uap;
187
188         crit_enter();
189
190         ATM_DEBUG2("uniarp_svcout: ivp=%p,dst=0x%x\n", ivp, dst->s_addr);
191
192         ivp->iv_arpent = NULL;
193
194         /*
195          * Get uni interface
196          */
197         uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
198         if (uip == NULL) {
199                 crit_exit();
200                 return (MAP_FAILED);
201         }
202
203         /*
204          * Lookup IP destination address
205          */
206         UNIARP_LOOKUP(dst->s_addr, uap);
207
208         if (uap) {
209                 /*
210                  * We've got an entry, verify interface
211                  */
212                 if (uap->ua_intf != uip) {
213                         crit_exit();
214                         return (MAP_FAILED);
215                 }
216
217                 /*
218                  * Chain this vcc onto entry
219                  */
220                 LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
221                 ivp->iv_arpent = (struct arpmap *)uap;
222                 uap->ua_flags |= UAF_USED;
223
224                 if (uap->ua_flags & UAF_VALID) {
225                         /*
226                          * Entry is valid, we're done
227                          */
228                         crit_exit();
229                         return (MAP_VALID);
230                 } else {
231                         /*
232                          * We're already looking for this address
233                          */
234                         crit_exit();
235                         return (MAP_PROCEEDING);
236                 }
237         }
238
239         /*
240          * No info in the cache.  If we're the server, then
241          * we're already authoritative, so just deny request.
242          * If we're a client but the server VCC isn't open we
243          * also deny the request.
244          */
245         if (uip->uip_arpstate != UIAS_CLIENT_ACTIVE) {
246                 crit_exit();
247                 return (MAP_FAILED);
248         }
249
250         /*
251          * We're a client with an open VCC to the server, get a new arp entry
252          */
253         uap = (struct uniarp *)atm_allocate(&uniarp_pool);
254         if (uap == NULL) {
255                 crit_exit();
256                 return (MAP_FAILED);
257         }
258
259         /*
260          * Get entry set up
261          */
262         uap->ua_dstip.s_addr = dst->s_addr;
263         uap->ua_dstatm.address_format = T_ATM_ABSENT;
264         uap->ua_dstatm.address_length = 0;
265         uap->ua_dstatmsub.address_format = T_ATM_ABSENT;
266         uap->ua_dstatmsub.address_length = 0;
267         uap->ua_intf = uip;
268
269         /*
270          * Link ipvcc to arp entry for later notification
271          */
272         LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
273         ivp->iv_arpent = (struct arpmap *)uap;
274         uap->ua_flags |= UAF_USED;
275
276         /*
277          * Add arp entry to table
278          */
279         UNIARP_ADD(uap);
280
281         /*
282          * Issue arp request for this address
283          */
284         uniarp_arp_req(uip, dst);
285
286         /*
287          * Start retry timer
288          */
289         UNIARP_TIMER(uap, UNIARP_ARP_RETRY);
290
291         crit_exit();
292         return (MAP_PROCEEDING);
293 }
294
295
296 /*
297  * Process a new incoming SVC requiring ATMARP support
298  * 
299  * This function is called by the IP/ATM module to resolve a caller's ATM
300  * address to its IP address for an incoming call in order to allow a
301  * bi-directional flow of IP packets on the SVC.  If a valid mapping is
302  * already in our cache, then we will use it.  Otherwise, we have to allocate
303  * a new arp entry and wait for the SVC to become active so that we can issue
304  * an InATMARP to the peer.
305  *
306  * Arguments:
307  *      ivp     pointer to SVC's IPVCC control block
308  *      dst     pointer to caller's ATM address
309  *      dstsub  pointer to caller's ATM subaddress
310  *
311  * Returns:
312  *      MAP_VALID       - Got the answer, returned via iv_arpent field.
313  *      MAP_PROCEEDING  - OK so far, querying for peer's mapping
314  *      MAP_FAILED      - error, unable to allocate resources
315  *
316  */
317 int
318 uniarp_svcin(struct ipvcc *ivp, Atm_addr *dst, Atm_addr *dstsub)
319 {
320         struct uniip    *uip;
321         struct uniarp   *uap;
322         int     found = 0, i;
323
324         crit_enter();
325
326         ATM_DEBUG1("uniarp_svcin: ivp=%p\n", ivp);
327
328         /*
329          * Clear ARP entry field
330          */
331         ivp->iv_arpent = NULL;
332
333         /*
334          * Check things out
335          */
336         if ((ivp->iv_flags & IVF_LLC) == 0)
337                 return (MAP_FAILED);
338
339         /*
340          * Get uni interface
341          */
342         uip = (struct uniip *)ivp->iv_ipnif->inf_isintf;
343         if (uip == NULL) {
344                 crit_exit();
345                 return (MAP_FAILED);
346         }
347
348         /*
349          * Make sure we're configured as a client or server
350          */
351         if (uip->uip_arpstate == UIAS_NOTCONF) {
352                 crit_exit();
353                 return (MAP_FAILED);
354         }
355
356         /*
357          * If we know the caller's ATM address, look it up
358          */
359         uap = NULL;
360         if (dst->address_format != T_ATM_ABSENT) {
361                 for (i = 0; (i < UNIARP_HASHSIZ) && (found == 0); i++) {
362                         for (uap = uniarp_arptab[i]; uap; uap = uap->ua_next) {
363                                 if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) &&
364                                     ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub)){
365                                         found = 1;
366                                         break;
367                                 }
368                         }
369                 }
370                 if (uap == NULL) {
371                         for (uap = uniarp_nomaptab; uap; uap = uap->ua_next) {
372                                 if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) &&
373                                     ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub))
374                                         break;
375                         }
376                 }
377         }
378
379         if (uap) {
380                 /*
381                  * We've got an entry, verify interface
382                  */
383                 if (uap->ua_intf != uip) {
384                         crit_exit();
385                         return (MAP_FAILED);
386                 }
387
388                 /*
389                  * Chain the vcc onto this entry
390                  */
391                 LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
392                 ivp->iv_arpent = (struct arpmap *)uap;
393                 uap->ua_flags |= UAF_USED;
394
395                 if (uap->ua_flags & UAF_VALID) {
396                         /*
397                          * Entry is valid, we're done
398                          */
399                         crit_exit();
400                         return (MAP_VALID);
401                 } else {
402                         /*
403                          * We're already looking for this address
404                          */
405                         crit_exit();
406                         return (MAP_PROCEEDING);
407                 }
408         }
409
410         /*
411          * No info in the cache - get a new arp entry
412          */
413         uap = (struct uniarp *)atm_allocate(&uniarp_pool);
414         if (uap == NULL) {
415                 crit_exit();
416                 return (MAP_FAILED);
417         }
418
419         /*
420          * Get entry set up
421          */
422         ATM_ADDR_COPY(dst, &uap->ua_dstatm);
423         ATM_ADDR_COPY(dstsub, &uap->ua_dstatmsub);
424         uap->ua_intf = uip;
425
426         /*
427          * Link ipvcc to arp entry for later notification
428          */
429         LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
430         ivp->iv_arpent = (struct arpmap *)uap;
431         uap->ua_flags |= UAF_USED;
432
433         /*
434          * Add arp entry to 'nomap' table
435          */
436         LINK2TAIL(uap, struct uniarp, uniarp_nomaptab, ua_next);
437
438         crit_exit();
439
440         /*
441          * Now we just wait for SVC to become active
442          */
443         return (MAP_PROCEEDING);
444 }
445
446
447 /*
448  * Process ARP SVC activation notification
449  *
450  * This function is called by the IP/ATM module whenever a previously
451  * opened SVC has successfully been connected.
452  *
453  * Arguments:
454  *      ivp     pointer to SVC's IPVCC control block
455  *
456  * Returns:
457  *      0       activation processing successful
458  *      errno   activation failed - reason indicated
459  *
460  */
461 int
462 uniarp_svcactive(struct ipvcc *ivp)
463 {
464         struct ip_nif   *inp;
465         struct uniip    *uip;
466         struct uniarp   *uap;
467         int     err;
468
469         crit_enter();
470
471         ATM_DEBUG1("uniarp_svcactive: ivp=%p\n", ivp);
472
473         inp = ivp->iv_ipnif;
474         uip = (struct uniip *)inp->inf_isintf;
475         uap = (struct uniarp *)ivp->iv_arpent;
476
477         /*
478          * First, we need to create our CM connection
479          */
480         err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc,
481                         ivp->iv_conn, &ivp->iv_arpconn);
482         if (err) {
483                 /*
484                  * We don't take no (or maybe) for an answer
485                  */
486                 if (ivp->iv_arpconn) {
487                         atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
488                         ivp->iv_arpconn = NULL;
489                 }
490                 return (err);
491         }
492
493         /*
494          * Is this the client->server vcc??
495          */
496         if (uip->uip_arpsvrvcc == ivp) {
497
498                 /*
499                  * Yep, go into the client registration phase
500                  */
501                 uip->uip_arpstate = UIAS_CLIENT_REGISTER;
502
503                 /*
504                  * To register ourselves, RFC1577 says we should wait
505                  * around for the server to send us an InATMARP_Request.
506                  * However, draft-1577+ just has us send an ATMARP_Request
507                  * for our own address.  To keep everyone happy, we'll go 
508                  * with both and see what works!
509                  */
510                 uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr));
511
512                 /*
513                  * Start retry timer
514                  */
515                 UNIIP_ARP_TIMER(uip, 1 * ATM_HZ);
516
517                 crit_exit();
518                 return (0);
519         }
520
521         /*
522          * Send an InATMARP_Request on this VCC to find out/notify who's at 
523          * the other end.  If we're the server, this will start off the
524          * RFC1577 registration procedure.  If we're a client, then this
525          * SVC is for user data and it's pretty likely that both ends are
526          * going to be sending packets.  So, if we're the caller, we'll be
527          * nice and let the callee know right away who we are.  If we're the
528          * callee, let's find out asap the caller's IP address.
529          */
530         uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp);
531
532         /*
533          * Start retry timer if entry isn't valid yet
534          */
535         if (((uap->ua_flags & UAF_VALID) == 0) &&
536             ((uap->ua_time.ti_flag & TIF_QUEUED) == 0))
537                 UNIARP_TIMER(uap, UNIARP_ARP_RETRY);
538
539         crit_exit();
540         return (0);
541 }
542
543
544 /*
545  * Process VCC close
546  * 
547  * This function is called just prior to IP/ATM closing a VCC which 
548  * supports ATMARP.  We'll sever our links to the VCC and then
549  * figure out how much more cleanup we need to do for now.
550  *
551  * Arguments:
552  *      ivp     pointer to VCC's IPVCC control block
553  *
554  * Returns:
555  *      none
556  *
557  */
558 void
559 uniarp_vcclose(struct ipvcc *ivp)
560 {
561         struct uniip    *uip;
562         struct uniarp   *uap;
563
564         ATM_DEBUG1("uniarp_vcclose: ivp=%p\n", ivp);
565
566         /*
567          * Close our CM connection
568          */
569         if (ivp->iv_arpconn) {
570                 atm_cm_release(ivp->iv_arpconn, &uniarp_cause);
571                 ivp->iv_arpconn = NULL;
572         }
573
574         /*
575          * Get atmarp entry
576          */
577         if ((uap = (struct uniarp *)ivp->iv_arpent) == NULL)
578                 return;
579         uip = uap->ua_intf;
580
581         crit_enter();
582
583         /*
584          * If this is the arpserver VCC, then schedule ourselves to
585          * reopen the connection soon
586          */
587         if (uip->uip_arpsvrvcc == ivp) {
588                 uip->uip_arpsvrvcc = NULL;
589                 uip->uip_arpstate = UIAS_CLIENT_POPEN;
590                 UNIIP_ARP_CANCEL(uip);
591                 UNIIP_ARP_TIMER(uip, 5 * ATM_HZ);
592         }
593
594         /*
595          * Remove IP VCC from chain
596          */
597         UNLINK(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext);
598
599         /*
600          * SVCs and PVCs are handled separately
601          */
602         if (ivp->iv_flags & IVF_SVC) {
603                 /*
604                  * If the mapping is currently valid or in use, or if there 
605                  * are other VCCs still using this mapping, we're done for now
606                  */
607                 if ((uap->ua_flags & (UAF_VALID | UAF_LOCKED)) ||
608                     (uap->ua_origin >= UAO_PERM) ||
609                     (uap->ua_ivp != NULL)) {
610                         crit_exit();
611                         return;
612                 }
613
614                 /*
615                  * Unlink the entry
616                  */
617                 if (uap->ua_dstip.s_addr == 0) {
618                         UNLINK(uap, struct uniarp, uniarp_nomaptab, ua_next);
619                 } else {
620                         UNIARP_DELETE(uap);
621                 }
622         } else {
623                 /*
624                  * Remove entry from pvc table
625                  */
626                 UNLINK(uap, struct uniarp, uniarp_pvctab, ua_next);
627         }
628
629         UNIARP_CANCEL(uap);
630
631         /*
632          * Finally, free the entry
633          */
634         atm_free((caddr_t)uap);
635
636         crit_exit();
637         return;
638 }
639
640
641 /*
642  * Process ATMARP VCC Connected Notification
643  * 
644  * Arguments:
645  *      toku    owner's connection token (ipvcc protocol block)
646  *
647  * Returns:
648  *      none
649  *
650  */
651 void
652 uniarp_connected(void *toku)
653 {
654
655         /*
656          * Since we only do atm_cm_addllc()'s on active connections,
657          * we should never get called here...
658          */
659         panic("uniarp_connected");
660 }
661
662
663 /*
664  * Process ATMARP VCC Cleared Notification
665  * 
666  * Arguments:
667  *      toku    owner's connection token (ipvcc protocol block)
668  *      cause   pointer to cause code
669  *
670  * Returns:
671  *      none
672  *
673  */
674 void
675 uniarp_cleared(void *toku, struct t_atm_cause *cause)
676 {
677         struct ipvcc    *ivp = toku;
678
679         crit_enter();
680
681         /*
682          * We're done with VCC
683          */
684         ivp->iv_arpconn = NULL;
685
686         /*
687          * If IP is finished with VCC, then we'll free it
688          */
689         if (ivp->iv_state == IPVCC_FREE)
690                 atm_free((caddr_t)ivp);
691
692         crit_exit();
693 }
694