Generally use NULL instead of explicitly casting 0 to some pointer type.
[games.git] / usr.sbin / atm / atmarpd / atmarp_scsp.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/usr.sbin/atm/atmarpd/atmarp_scsp.c,v 1.3 1999/08/28 01:15:30 peter Exp $
27  *      @(#) $DragonFly: src/usr.sbin/atm/atmarpd/atmarp_scsp.c,v 1.4 2004/12/18 22:48:02 swildner Exp $
28  */
29
30 /*
31  * Server Cache Synchronization Protocol (SCSP) Support
32  * ----------------------------------------------------
33  *
34  * SCSP-ATMARP server interface: SCSP/ATMARP interface code
35  *
36  */
37
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
41 #include <net/if.h>
42 #include <netinet/in.h>
43 #include <netatm/port.h>
44 #include <netatm/queue.h>
45 #include <netatm/atm.h>
46 #include <netatm/atm_if.h>
47 #include <netatm/atm_sap.h>
48 #include <netatm/atm_sys.h>
49 #include <netatm/atm_ioctl.h>
50 #include <netatm/uni/uniip_var.h>
51  
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <libatm.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <syslog.h>
59 #include <unistd.h>
60
61 #include "../scspd/scsp_msg.h"
62 #include "../scspd/scsp_if.h"
63 #include "../scspd/scsp_var.h"
64 #include "atmarp_var.h"
65
66 /*
67  * Send the cache for a LIS to SCSP
68  *
69  *
70  * Arguments:
71  *      aip     pointer to interface block
72  *
73  * Returns:
74  *      0       cache sent to SCSP OK
75  *      errno   reason for failure
76  *
77  */
78 int
79 atmarp_scsp_cache(Atmarp_intf *aip, Scsp_if_msg *msg)
80 {
81         int             i, len, rc = 0;
82         Atmarp          *aap;
83         Scsp_if_msg     *smp = NULL;
84         Scsp_atmarp_msg *sap;
85
86         /*
87          * Figure out how big the message needs to be
88          */
89         len = sizeof(Scsp_if_msg_hdr);
90         for (i = 0; i < ATMARP_HASHSIZ; i++) {
91                 for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) {
92                         len += sizeof(Scsp_atmarp_msg);
93                 }
94         }
95
96         /*
97          * Get memory for the cache message
98          */
99         smp = (Scsp_if_msg *)UM_ALLOC(len);
100         if (!smp) {
101                 atmarp_mem_err("atmarp_scsp_cache: len");
102         }
103         UM_ZERO(smp, len);
104
105         /*
106          * Set header fields in SCSP message
107          */
108         smp->si_type = SCSP_CACHE_RSP;
109         smp->si_proto = SCSP_PROTO_ATMARP;
110         smp->si_len = len;
111         smp->si_tok = msg->si_tok;
112
113         /*
114          * Loop through the cache, adding each entry to the SCSP
115          * Cache Response message
116          */
117         sap = &smp->si_atmarp;
118         for (i = 0; i < ATMARP_HASHSIZ; i++) {
119                 for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) {
120                         sap->sa_state = SCSP_ASTATE_NEW;
121                         sap->sa_cpa = aap->aa_dstip;
122                         ATM_ADDR_COPY(&aap->aa_dstatm, &sap->sa_cha);
123                         ATM_ADDR_COPY(&aap->aa_dstatmsub, &sap->sa_csa);
124                         sap->sa_key = aap->aa_key;
125                         sap->sa_oid = aap->aa_oid;
126                         sap->sa_seq = aap->aa_seq;
127                         sap++;
128                 }
129         }
130
131         /*
132          * Send the message to SCSP
133          */
134         rc = atmarp_scsp_out(aip, (char *)smp, len);
135
136         /*
137          * Free the message
138          */
139         if (smp)
140                 UM_FREE(smp);
141
142         return(rc);
143 }
144
145
146 /*
147  * Answer a reqeust for information about a cache entry
148  *
149  * Arguments:
150  *      aap     pointer to entry
151  *      state   entry's new state
152  *
153  * Returns:
154  *      0       success
155  *      errno   reason for failure
156  *
157  */
158 int
159 atmarp_scsp_solicit(Atmarp_intf *aip, Scsp_if_msg *smp)
160 {
161         int             i, rc = 0;
162         Atmarp          *aap;
163         Scsp_if_msg     *rsp = NULL;
164
165         /*
166          * Search the interface's ATMARP cache for an entry with
167          * the specified cache key and origin ID
168          */
169         for (i = 0; i < ATMARP_HASHSIZ; i++) {
170                 for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) {
171                         if (KEY_EQUAL(&aap->aa_key,
172                                         &smp->si_sum.ss_key) &&
173                                         OID_EQUAL(&aap->aa_oid,
174                                         &smp->si_sum.ss_oid))
175                                 break;
176                 }
177                 if (aap)
178                         break;
179         }
180
181         /*
182          * Get storage for a Solicit Response
183          */
184         rsp = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg));
185         if (!rsp) {
186                 atmarp_mem_err("atmarp_scsp_solicit: sizeof(Scsp_if_msg)");
187         }
188         UM_ZERO(rsp, sizeof(Scsp_if_msg));
189
190         /*
191          * Fill out the Solicit Rsp
192          */
193         rsp->si_type = SCSP_SOLICIT_RSP;
194         rsp->si_proto = smp->si_proto;
195         rsp->si_tok = smp->si_tok;
196
197         if (aap) {
198                 /*
199                  * Copy fields from the ATMARP entry to the SCSP
200                  * Update Request message
201                  */
202                 rsp->si_rc = SCSP_RSP_OK;
203                 rsp->si_len = sizeof(Scsp_if_msg_hdr) +
204                                 sizeof(Scsp_atmarp_msg);
205                 rsp->si_atmarp.sa_state = SCSP_ASTATE_UPD;
206                 rsp->si_atmarp.sa_cpa = aap->aa_dstip;
207                 ATM_ADDR_COPY(&aap->aa_dstatm, &rsp->si_atmarp.sa_cha);
208                 ATM_ADDR_COPY(&aap->aa_dstatmsub, &rsp->si_atmarp.sa_csa);
209                 rsp->si_atmarp.sa_key = aap->aa_key;
210                 rsp->si_atmarp.sa_oid = aap->aa_oid;
211                 rsp->si_atmarp.sa_seq = aap->aa_seq;
212         } else {
213                 /*
214                  * Entry not found--set return code
215                  */
216                 rsp->si_rc = SCSP_RSP_NOT_FOUND;
217                 rsp->si_len = smp->si_len;
218                 rsp->si_sum = smp->si_sum;
219         }
220
221         /*
222          * Send the message to SCSP
223          */
224         rc = atmarp_scsp_out(aip, (char *)rsp, rsp->si_len);
225         UM_FREE(rsp);
226
227         return(rc);
228 }
229
230
231 /*
232  * Send a cache update to SCSP
233  *
234  * Arguments:
235  *      aap     pointer to entry
236  *      state   entry's new state
237  *
238  * Returns:
239  *      0       success
240  *      errno   reason for failure
241  *
242  */
243 int
244 atmarp_scsp_update(Atmarp *aap, int state)
245 {
246         int             rc = 0;
247         Atmarp_intf     *aip = aap->aa_intf;
248         Scsp_if_msg     *smp = NULL;
249
250         /*
251          * Make sure the connection to SCSP is active
252          */
253         if (aip->ai_state == AI_STATE_NULL) {
254                 return(0);
255         }
256
257         /*
258          * Get memory for the cache message
259          */
260         smp = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg));
261         if (!smp) {
262                 atmarp_mem_err("atmarp_scsp_update: sizeof(Scsp_if_msg)");
263         }
264         UM_ZERO(smp, sizeof(Scsp_if_msg));
265
266         /*
267          * Set header fields in SCSP message
268          */
269         smp->si_type = SCSP_UPDATE_REQ;
270         smp->si_proto = SCSP_PROTO_ATMARP;
271         smp->si_len = sizeof(Scsp_if_msg_hdr) + sizeof(Scsp_atmarp_msg);
272
273         /*
274          * Copy fields from the ATMARP entry to the SCSP
275          * Update Request message
276          */
277         smp->si_atmarp.sa_state = state;
278         smp->si_atmarp.sa_cpa = aap->aa_dstip;
279         ATM_ADDR_COPY(&aap->aa_dstatm, &smp->si_atmarp.sa_cha);
280         ATM_ADDR_COPY(&aap->aa_dstatmsub, &smp->si_atmarp.sa_csa);
281         smp->si_atmarp.sa_key = aap->aa_key;
282         smp->si_atmarp.sa_oid = aap->aa_oid;
283         smp->si_atmarp.sa_seq = aap->aa_seq;
284
285         /*
286          * Send the message to SCSP
287          */
288         rc = atmarp_scsp_out(aap->aa_intf, (char *)smp, smp->si_len);
289
290         UM_FREE(smp);
291         return(rc);
292 }
293
294
295 /*
296  * Respond to a Cache Update Indication from SCSP
297  *
298  *
299  * Arguments:
300  *      aip     pointer to interface control block
301  *      smp     pointer to message from SCSP
302  *
303  * Returns:
304  *      0       Message processed OK
305  *      errno   Reason for failure
306  *
307  */
308 int
309 atmarp_scsp_update_in(Atmarp_intf *aip, Scsp_if_msg *smp)
310 {
311         int     accept, rc;
312         Atmarp  *aap;
313
314         /*
315          * Look up the entry
316          */
317         ATMARP_LOOKUP(aip, smp->si_atmarp.sa_cpa.s_addr, aap);
318
319         /*
320          * Whether we accept the request depends on whether we
321          * already have an entry for it
322          */
323          if (!aap) {
324                 /*
325                  * We don't have this entry--accept it
326                  */
327                 accept = 1;
328         } else {
329                 /*
330                  * We do have an entry for this host--check the
331                  * origin ID
332                  */
333                 if (bcmp(&aip->ai_ip_addr.s_addr,
334                                 smp->si_atmarp.sa_oid.id,
335                                 SCSP_ATMARP_ID_LEN) == 0) {
336                         /*
337                          * The received entry originated with us--
338                          * reject it
339                          */
340                         accept = 0;
341                 } else if (bcmp(&aip->ai_ip_addr.s_addr,
342                                 aap->aa_oid.id,
343                                 SCSP_ATMARP_ID_LEN) == 0) {
344                         /*
345                          * We originated the entry we currently have--
346                          * only accept the new one if SCSP has higher
347                          * priority than the existing entry
348                          */
349                         accept = aap->aa_origin < UAO_SCSP;
350                 } else {
351                         /*
352                          * Accept the entry if it is more up-to-date
353                          * than the existing entry
354                          */
355                         accept = KEY_EQUAL(&aap->aa_key,
356                                         &smp->si_atmarp.sa_key) &&
357                                 OID_EQUAL(&aap->aa_oid,
358                                         &smp->si_atmarp.sa_oid) &&
359                                 (aap->aa_seq < smp->si_atmarp.sa_seq);
360                 }
361         }
362
363         /*
364          * Add the entry to the cache, if appropriate
365          */
366         if (accept) {
367                 if (!aap) {
368                         /*
369                          * Copy info from SCSP to a new cache entry
370                          */
371                         aap = (Atmarp *)UM_ALLOC(sizeof(Atmarp));
372                         if (!aap)
373                                 atmarp_mem_err("atmarp_scsp_update_in: sizeof(Atmarp)");
374                         UM_ZERO(aap, sizeof(Atmarp));
375
376                         aap->aa_dstip = smp->si_atmarp.sa_cpa;
377                         aap->aa_dstatm = smp->si_atmarp.sa_cha;
378                         aap->aa_dstatmsub = smp->si_atmarp.sa_csa;
379                         aap->aa_key = smp->si_atmarp.sa_key;
380                         aap->aa_oid = smp->si_atmarp.sa_oid;
381                         aap->aa_seq = smp->si_atmarp.sa_seq;
382                         aap->aa_intf = aip;
383                         aap->aa_origin = UAO_SCSP;
384
385                         /*
386                          * Add the new entry to our cache
387                          */
388                         ATMARP_ADD(aip, aap);
389                 } else {
390                         /*
391                          * Update the existing entry
392                          */
393                         aap->aa_dstip = smp->si_atmarp.sa_cpa;
394                         aap->aa_dstatm = smp->si_atmarp.sa_cha;
395                         aap->aa_dstatmsub = smp->si_atmarp.sa_csa;
396                         aap->aa_key = smp->si_atmarp.sa_key;
397                         aap->aa_oid = smp->si_atmarp.sa_oid;
398                         aap->aa_seq = smp->si_atmarp.sa_seq;
399                         aap->aa_origin = UAO_SCSP;
400                 }
401
402                 /*
403                  * Send the updated entry to the kernel
404                  */
405                 if (atmarp_update_kernel(aap) == 0)
406                         rc = SCSP_RSP_OK;
407                 else
408                         rc = SCSP_RSP_REJ;
409         } else {
410                 rc = SCSP_RSP_REJ;
411         }
412
413         /*
414          * Turn the received message into a response
415          */
416         smp->si_type = SCSP_UPDATE_RSP;
417         smp->si_rc = rc;
418
419         /*
420          * Send the message to SCSP
421          */
422         rc = atmarp_scsp_out(aip, (char *)smp, smp->si_len);
423
424         return(rc);
425 }
426
427
428 /*
429  * Read and process a message from SCSP
430  *
431  *
432  * Arguments:
433  *      aip     interface for read
434  *
435  * Returns:
436  *      0       success
437  *      errno   reason for failure
438  *
439  */
440 int
441 atmarp_scsp_read(Atmarp_intf *aip)
442 {
443         int             len, rc = 0;
444         char            *buff = NULL;
445         Scsp_if_msg     *smp;
446         Scsp_if_msg_hdr msg_hdr;
447
448         /*
449          * Read the header of the message from SCSP
450          */
451         len = read(aip->ai_scsp_sock, (char *)&msg_hdr,
452                         sizeof(msg_hdr));
453         if (len == -1) {
454                 rc = errno;
455                 goto read_fail;
456         } else if (len != sizeof(msg_hdr)) {
457                 rc = EMSGSIZE;
458                 goto read_fail;
459         }
460
461         /*
462          * Get a buffer that will hold the message
463          */
464         buff = UM_ALLOC(msg_hdr.sh_len);
465         if (!buff)
466                 atmarp_mem_err("atmarp_scsp_read: msg_hdr.sh_len");
467         UM_COPY(&msg_hdr, buff, sizeof(msg_hdr));
468
469         /*
470          * Read the rest of the message, if there is more than
471          * just a header
472          */
473         len = msg_hdr.sh_len - sizeof(msg_hdr);
474         if (len > 0) {
475                 len = read(aip->ai_scsp_sock, buff + sizeof(msg_hdr),
476                                 len);
477                 if (len == -1) {
478                         rc = errno;
479                         goto read_fail;
480                 } else if (len != msg_hdr.sh_len - sizeof(msg_hdr)) {
481                         rc = EMSGSIZE;
482                         goto read_fail;
483                 }
484         }
485
486         /*
487          * Handle the message based on its type
488          */
489         smp = (Scsp_if_msg *)buff;
490         switch(smp->si_type) {
491         case SCSP_CFG_RSP:
492                 if (smp->si_rc != SCSP_RSP_OK) {
493                         rc = EINVAL;
494                         goto read_fail;
495                 }
496                 break;
497         case SCSP_CACHE_IND:
498                 rc = atmarp_scsp_cache(aip, smp);
499                 break;
500         case SCSP_SOLICIT_IND:
501                 rc = atmarp_scsp_solicit(aip, smp);
502                 break;
503         case SCSP_UPDATE_IND:
504                 rc = atmarp_scsp_update_in(aip, smp);
505                 break;
506         case SCSP_UPDATE_RSP:
507                 /*
508                  * Ignore Update Responses
509                  */
510                 break;
511         default:
512                 atmarp_log(LOG_ERR, "Unexpected SCSP message received");
513                 return(EOPNOTSUPP);
514         }
515
516         UM_FREE(buff);
517         return(rc);
518
519 read_fail:
520         if (buff) {
521                 UM_FREE(buff);
522         }
523
524         /*
525          * Error on socket to SCSP--close the socket and set the state
526          * so that we know to retry when the cache timer fires.
527          */
528         atmarp_scsp_close(aip);
529
530         return(rc);
531 }
532
533
534 /*
535  * Send a message to SCSP
536  *
537  *
538  * Arguments:
539  *      aip     pointer to ATMARP interface to send message on
540  *      buff    pointer to message buffer
541  *      len     length of message
542  *
543  * Returns:
544  *      0       message sent
545  *      errno   reason for failure
546  *
547  */
548 int
549 atmarp_scsp_out(Atmarp_intf *aip, char *buff, int len)
550 {
551         int     rc;
552
553         /*
554          * Send the message to SCSP
555          */
556         rc = write(aip->ai_scsp_sock, buff, len);
557         if (rc == len)
558                 return(0);
559
560         /*
561          * Error on write--close the socket to SCSP, clean up and
562          * set the state so that we know to retry when the cache
563          * timer fires.
564          */
565         atmarp_scsp_close(aip);
566
567         /*
568          * Set the return code
569          */
570         if (rc < 0) {
571                 rc = errno;
572         } else {
573                 rc = EFAULT;
574         }
575
576         return(rc);
577 }
578
579
580 /*
581  * Set up a socket and connect to SCSP
582  *
583  * Arguments:
584  *      aip     pointer to interface block
585  *
586  * Returns:
587  *      0       success, ai_scsp_sock is set
588  *      errno   reason for failure
589  *
590  *
591  */
592 int
593 atmarp_scsp_connect(Atmarp_intf *aip)
594 {
595         int             len, rc, sd;
596         char            *sn;
597         Scsp_if_msg     cfg_msg;
598
599         static struct sockaddr  local_addr = {
600 #if (defined(BSD) && (BSD >= 199103))
601                 sizeof(struct sockaddr),        /* sa_len */
602 #endif
603                 AF_UNIX,                        /* sa_family */
604                 ATMARP_SOCK_PREFIX              /* sa_data */
605         };
606         static struct sockaddr  scsp_addr = {
607 #if (defined(BSD) && (BSD >= 199103))
608                 sizeof(struct sockaddr),        /* sa_len */
609 #endif
610                 AF_UNIX,                        /* sa_family */
611                 SCSPD_SOCK_NAME                 /* sa_data */
612         };
613
614         /*
615          * Construct a name for the socket
616          */
617         strncpy(local_addr.sa_data, ATMARP_SOCK_PREFIX,
618                         sizeof(local_addr.sa_data));
619         strncat(local_addr.sa_data, aip->ai_intf, sizeof(local_addr.sa_data));
620         sn = strdup(local_addr.sa_data);
621         if (!sn)
622                 atmarp_mem_err("atmarp_scsp_connect: strdup");
623
624         /*
625          * Clean up any old socket
626          */
627         rc = unlink(sn);
628         if (rc < 0 && errno != ENOENT)
629                 return(errno);
630
631         /*
632          * Open a socket to SCSP
633          */
634         sd = socket(PF_UNIX, SOCK_STREAM, 0);
635         if (sd == -1) {
636                 UM_FREE(sn);
637                 return(errno);
638         }
639         if (sd > atmarp_max_socket) {
640                 atmarp_max_socket = sd;
641         }
642
643         /*
644          * Set non-blocking I/O
645          */
646 #ifdef sun
647         rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY);
648 #else
649         rc = fcntl(sd, F_SETFL, O_NONBLOCK);
650 #endif
651         if (rc == -1) {
652                 rc = errno;
653                 goto scsp_connect_fail;
654         }
655
656         /*
657          * Bind the local socket address
658          */
659         rc = bind(sd, &local_addr, sizeof(local_addr));
660         if (rc) {
661                 rc = errno;
662                 goto scsp_connect_fail;
663         }
664
665         /*
666          * Connect to SCSP
667          */
668         rc = connect(sd, &scsp_addr, sizeof(scsp_addr));
669         if (rc) {
670                 rc = errno;
671                 goto scsp_connect_fail;
672         }
673
674         /*
675          * Save socket information in interface control block
676          */
677         aip->ai_scsp_sock = sd;
678         aip->ai_scsp_sockname = sn;
679         aip->ai_state = AI_STATE_UP;
680
681         /*
682          * Send configuration information to SCSP
683          */
684         UM_ZERO(&cfg_msg, sizeof(cfg_msg));
685         cfg_msg.si_type = SCSP_CFG_REQ;
686         cfg_msg.si_proto = SCSP_PROTO_ATMARP;
687         strcpy(cfg_msg.si_cfg.atmarp_netif, aip->ai_intf);
688         len =sizeof(Scsp_if_msg_hdr) + strlen(aip->ai_intf) + 1;
689         cfg_msg.si_len = len;
690         rc = atmarp_scsp_out(aip, (char *)&cfg_msg, len);
691         if (rc) {
692                 return(rc);
693         }
694
695         return(0);
696
697 scsp_connect_fail:
698         close(sd);
699         aip->ai_scsp_sock = -1;
700         UM_FREE(sn);
701         aip->ai_scsp_sockname = NULL;
702         aip->ai_state = AI_STATE_NULL;
703         return(rc);
704 }
705
706
707 /*
708  * Close a socket connection to SCSP
709  *
710  * Arguments:
711  *      aip     pointer to interface block for connection to be closed
712  *
713  * Returns:
714  *      none
715  *
716  *
717  */
718 void
719 atmarp_scsp_close(Atmarp_intf *aip)
720 {
721         /*
722          * Close and unlink the SCSP socket
723          */
724         close(aip->ai_scsp_sock);
725         aip->ai_scsp_sock = -1;
726         unlink(aip->ai_scsp_sockname);
727         UM_FREE(aip->ai_scsp_sockname);
728         aip->ai_scsp_sockname = NULL;
729
730         aip->ai_state = AI_STATE_NULL;
731
732         return;
733 }
734
735
736 /*
737  * Disconnect an interface from SCSP
738  *
739  * Arguments:
740  *      aip     pointer to interface block for connection to be closed
741  *
742  * Returns:
743  *      0       success, ai_scsp_sock is set
744  *      errno   reason for failure
745  *
746  *
747  */
748 int
749 atmarp_scsp_disconnect(Atmarp_intf *aip)
750 {
751         int     i;
752         Atmarp  *aap;
753
754         /*
755          * Close and unlink the SCSP socket
756          */
757         atmarp_scsp_close(aip);
758
759         /*
760          * Free the ATMARP cache associated with the interface
761          */
762         for (i = 0; i < ATMARP_HASHSIZ; i++) {
763                 for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) {
764                         UM_FREE(aap);
765                 }
766                 aip->ai_arptbl[i] = NULL;
767         }
768
769         return(0);
770 }