www.usr.com/support/gpl/USR9107_release.1.4.tar.gz
[bcm963xx.git] / userapps / opensource / atm2684 / pvc2684ctl / pvc2684d.c
1 /* brpvcd.c -- daemon for managing RFC2684 bridge-encapsulation VCs
2
3    written by Chuck Musser <chuckie@well.com>
4    based on br2684ctl, by Marcel GAL <cell@sch.bme.hu>
5 */
6
7 #include <stdio.h>             /* printf, read, write, etc.  */
8 #include <stdlib.h>            /* malloc, exit, etc.         */
9 #include <stdarg.h>            /* var args support.          */
10 #include <unistd.h>            /* close, unlink, etc.        */
11 #include <syslog.h>            /* System logging interface   */
12 #include <errno.h>             /* system errors              */
13 #include <sys/un.h>            /* unix domain sockets        */
14 #include <sys/stat.h>          /* stat, chmod                */
15 #include <sys/types.h>         /* u_int32_t, etc.            */
16 #include <sys/ioctl.h>         /* ioctl, etc.                */
17 // brcm
18 #include "atm.h"               /* general ATM stuff          */
19 #include "atmdev.h"      /* ATM device ioctls          */   
20 #include "atmbr2684.h"   /* ATM bridging structs       */
21 #include "atmrt2684.h"   /* ATM bridging structs       */
22
23 #include "brpvc.h"
24
25 // brcm
26 #define OFFSET 100000
27
28 struct be_group group_head;
29 struct be_memstat memstat = {0,0,0,0};
30
31 void do_error (int priority, const char *fmt, ...)
32 {
33   va_list args;
34   char buf[80];
35
36   va_start(args,fmt);
37   vsnprintf(buf,sizeof(buf),fmt,args);
38   syslog(priority,buf);
39   va_end(args);
40   
41   if(priority == LOG_ERR) {
42     unlink(BRPVC_SOCKPATH);
43     exit(-1);
44   }
45 }
46
47 // brcm
48 setIndexName(char * str, const char * hdr, int index) {
49     int num1, num2;
50     
51     num1 = index/OFFSET;
52     num2 = index - OFFSET*num1;
53     sprintf(str, "%s_%d_%d", hdr, num1, num2);
54 }
55
56 // brcm
57 int create_br(int nas_idx, int mode)
58 //int create_br(int nas_idx)
59 {
60   int sock, result = 0;
61   struct atm_newif_br2684 ni;
62   // brcm
63   struct atm_newif_rt2684 ni_rt;
64   int ret = 0;
65
66   if((sock = socket(PF_ATMPVC, SOCK_DGRAM, ATM_AAL5)) < 0)
67
68     do_error(LOG_WARNING, "socket creation failed for nas%d: %s",nas_idx,strerror(errno));
69
70   else {
71     
72     /* Create the the bridge-encapsulation interface.
73      */
74     // brcm
75     if (!mode) {
76         ni.backend_num = ATM_BACKEND_BR2684;
77         ni.media       = BR2684_MEDIA_ETHERNET;
78         ni.mtu         = 1500;
79         // brcm
80         setIndexName(ni.ifname, "nas", nas_idx);
81         //sprintf(ni.ifname, "nas_%d", nas_idx);
82     } else {
83         ni_rt.backend_num = ATM_BACKEND_RT2684;
84         // brcm
85         setIndexName(ni_rt.ifname, "ipa", nas_idx);
86         //sprintf(ni_rt.ifname, "atm_%d", nas_idx);
87     }
88     // brcm
89     /*
90     ni.backend_num = ATM_BACKEND_BR2684;
91     ni.media       = BR2684_MEDIA_ETHERNET;
92     ni.mtu         = 1500;
93     sprintf(ni.ifname, "nas%d", nas_idx);
94     */
95     // brcm
96     if (!mode)
97         ret=ioctl (sock, ATM_NEWBACKENDIF, &ni);
98     else
99         ret=ioctl (sock, ATM_NEWBACKENDIF, &ni_rt);
100     if (ret < 0) {
101       
102       if(errno == EEXIST) {
103
104         /* It's not fatal to create an interface that already exists.
105            We probably will end up doing it all the time because there's
106            no way to delete interfaces. Not a problem.
107         */
108         /*      do_error(LOG_INFO, "Interface %s already exists", ni.ifname);  */
109         result = 1;
110
111       } else
112         do_error(LOG_WARNING, "Can't create interface : %s", strerror(errno));
113     } else {
114
115       do_error(LOG_INFO, "Interface \"%s\" created sucessfully\n",mode? ni_rt.ifname:ni.ifname);
116       result = 1;
117     }
118   }
119   close(sock);
120   return result;
121 }
122
123 // brcm
124 int assign_vcc(struct sockaddr_atmpvc addr, int nas_idx, int encap, int bufsize, int proto_filter, int mode, \
125         unsigned short  vlan_id)
126 //int assign_vcc(struct sockaddr_atmpvc addr, int nas_idx, int encap, int bufsize)
127 {
128   int fd;
129   struct atm_qos qos;
130   struct atm_backend_br2684 be;
131   // brcm
132   struct atm_backend_rt2684 be_rt;
133   int ret=0;
134
135   if ((fd = socket(PF_ATMPVC, SOCK_DGRAM, ATM_AAL5)) < 0) {
136     do_error(LOG_WARNING,"failed to create socket, reason: %s", strerror(errno));
137     return -1;
138   }
139   
140   memset(&qos, 0, sizeof(qos));
141   qos.aal                     = ATM_AAL5;
142   qos.txtp.traffic_class      = ATM_UBR;
143   qos.txtp.max_sdu            = 1524;
144   qos.txtp.pcr                = ATM_MAX_PCR;
145   qos.rxtp = qos.txtp;
146     
147   if( setsockopt(fd,SOL_SOCKET,SO_SNDBUF, &bufsize ,sizeof(bufsize)) < 0) {
148     do_error(LOG_WARNING,"setsockopt SO_SNDBUF: (%d) %s\n",bufsize, strerror(errno));
149     return -1;
150   }
151
152   if( setsockopt(fd, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0) {
153     do_error(LOG_WARNING,"setsockopt SO_ATMQOS %s", strerror(errno));
154     return -1;
155   }
156
157   if( connect(fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_atmpvc)) < 0) {
158     do_error(LOG_WARNING,"failed to connect on socket: %s", strerror(errno));
159     return -1;
160   }
161   
162   /* attach the vcc to device.
163    */
164   // brcm
165   if (!mode) {
166   // brcm
167   be.backend_num   = ATM_BACKEND_BR2684;
168   be.ifspec.method = BR2684_FIND_BYIFNAME;
169   // brcm
170   setIndexName(be.ifspec.spec.ifname, "nas", nas_idx);
171   //sprintf(be.ifspec.spec.ifname, "nas_%d", nas_idx);
172   be.fcs_in        = BR2684_FCSIN_NO;
173   be.fcs_out       = BR2684_FCSOUT_NO;
174   be.fcs_auto      = 0;
175   be.encaps        = encap;
176   be.has_vpiid     = 0;
177   be.send_padding  = 0;
178   be.min_size      = 0;
179   // brcm
180   be.proto_filter  = proto_filter;
181   be.vlan_id = vlan_id;
182
183   // brcm
184   } else {
185     be_rt.backend_num   = ATM_BACKEND_RT2684;
186     be_rt.ifspec.method = BR2684_FIND_BYIFNAME;
187     // brcm
188     setIndexName(be_rt.ifspec.spec.ifname, "ipa", nas_idx);
189     //sprintf(be_rt.ifspec.spec.ifname, "atm_%d", nas_idx);
190     be_rt.encaps        = encap;
191   }
192
193   // brcm
194   if (!mode)
195       ret = ioctl (fd, ATM_SETBACKEND, &be);
196   else
197       ret = ioctl (fd, ATM_SETBACKEND, &be_rt);
198   if( ret == 0) {
199     do_error(LOG_INFO,"Communicating over ATM %d.%d.%d, encapsulation: %s\n", 
200              addr.sap_addr.itf,
201              addr.sap_addr.vpi,
202              addr.sap_addr.vci,
203              encap ? "LLC" : "VC mux");
204     return fd;
205   } else {
206     do_error(LOG_WARNING,"Could not configure interface:%s",strerror(errno));
207     return -1;
208   }
209 }
210
211
212 void do_add(int cli_fd, struct be_msg *rmsg, struct ucred *cli_cred)
213 {
214   static struct be_group *group = &group_head;
215   static struct be_vc *prev_vc = NULL;
216   static char curr_groupname[MAX_GROUPNAME_LEN] = {};
217   static pid_t curr_cli_pid = 0;
218
219   struct be_group *last_group = NULL, *new_group;
220   struct be_vc *new_vc;
221   struct be_msg smsg;
222   int sock;
223
224   /* New client instance means that we reset the current working group.
225    */
226   if(curr_cli_pid != cli_cred->pid) {
227     curr_groupname[0] = '\0';
228     group = &group_head;
229     curr_cli_pid = cli_cred->pid;
230   }
231
232 // brcm
233   if(create_br(rmsg->nas_idx, rmsg->mode) == 0) {
234 //  if(create_br(rmsg->nas_idx) == 0) {
235
236     smsg.msgtype = INTERFACE_FAILED;
237     if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
238       do_error(LOG_WARNING,"do_add() couldn't send interface creation failure message.");
239     return;
240   }
241
242 // brcm
243   if( (sock = assign_vcc(rmsg->pvc, rmsg->nas_idx, rmsg->encap, 8192, rmsg->proto_filter, rmsg->mode, \
244           rmsg->vlan_id)) < 0) {
245 //  if( (sock = assign_vcc(rmsg->pvc, rmsg->nas_idx, BR2684_ENCAPS_LLC, 8192)) < 0) {
246     
247     smsg.msgtype = SOCK_FAILED;
248     if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
249       do_error(LOG_WARNING,"do_add() couldn't send socket creation failure message.");
250     return;
251   }
252
253   /* See if this group is different from the last one. If isn't, we simply pick up where
254      we left off last time with the group and vc pointers stored in static variables.
255      This is more efficient for multiple adds, because we always want go to the end of 
256      the current group's VC list.
257   */
258   if( strncmp(rmsg->name,curr_groupname,MAX_GROUPNAME_LEN) ) {
259     
260     /* This groupname is different from the last one. Remember it for next time.
261      */
262
263     strncpy(curr_groupname,rmsg->name,MAX_GROUPNAME_LEN); 
264
265     /* Does this group exist?  
266      */
267     for(group = &group_head; group != NULL; group = group->next) {
268       last_group = group;
269       if(!strncmp(rmsg->name,group->name,MAX_GROUPNAME_LEN)) 
270         break;
271     }
272
273     if(!group) {
274
275       /* Nope.  Create a new group.
276        */
277       if(! (new_group = (struct be_group *)malloc(sizeof(struct be_group))) ) {
278         do_error(LOG_WARNING,"can't allocate memory for new group %s", rmsg->name);
279         
280         close(sock);
281         smsg.msgtype = NOMEM;
282         if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
283           do_error(LOG_WARNING,"do_add() couldn't send malloc failure message for new group.");
284         return;
285       }
286   
287       memstat.group_mallocs++;
288
289       last_group->next      = new_group;
290       new_group->head       = NULL;
291       new_group->next       = NULL;
292       strncpy(new_group->name,rmsg->name,MAX_GROUPNAME_LEN);
293       
294       /* set prev_vc to the VC list head.
295        */
296       group = new_group;
297       prev_vc = group->head;
298     } else
299
300       /* Ratchet to the end of an existing group VC list.
301        */
302       for(prev_vc = group->head; prev_vc->next != NULL; prev_vc=prev_vc->next);
303   }
304
305   /* Create the new VC
306    */
307   if(! (new_vc = (struct be_vc *)malloc(sizeof(struct be_vc))) ) {
308     do_error(LOG_WARNING,"can't allocate memory for new vc %d/%d on nas%d\n",
309              rmsg->pvc.sap_addr.vpi,
310              rmsg->pvc.sap_addr.vci,
311              rmsg->nas_idx
312              );
313
314     close(sock);
315     smsg.msgtype = NOMEM;
316     if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
317       do_error(LOG_WARNING,"do_add() couldn't send malloc failure message for new VC.");
318     return;
319   }
320   
321   memstat.vc_mallocs++;
322   
323   new_vc->nas_idx  = rmsg->nas_idx;
324   memcpy(&new_vc->pvc, &rmsg->pvc, sizeof(struct sockaddr_atmpvc));
325   new_vc->sock    = sock;
326   new_vc->uid     = cli_cred->uid;
327   new_vc->vlan_id = rmsg->vlan_id;
328   new_vc->next    = NULL;
329   
330   /* Add the new VC to the end of the list and remember the
331      new end for next time. This "if" block is neccessary because
332      we cannot initialize prev_vc with the address of group_head.pvc,
333      which is non-constant. My intent is to keep most of the state 
334      variables local to this function.
335   */
336
337   if(!group->head)
338     group->head = new_vc;
339   else if(prev_vc) 
340     prev_vc->next = new_vc;
341
342   prev_vc       = new_vc;
343   
344   smsg.msgtype = OK;
345   if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
346     do_error(LOG_ERR,"do_add couldn't send OK response: %s",strerror(errno));           
347 }
348
349 // brcm
350 int delete_br(int num)
351 //int delete_br(char *nstr)
352 {
353 //  int num, err;
354   int err;
355   int sock;
356
357   sock = socket(PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
358   if (sock<0) {
359     syslog(LOG_ERR, "socket creation failed: %s",strerror(errno));
360   } else {
361     /* create the device with ioctl: */
362     //num=atoi(nstr);
363     if( num>=0 && num<1234567890){
364       struct atm_newif_br2684 ni;
365       ni.backend_num = ATM_BACKEND_BR2684;
366       ni.media = BR2684_MEDIA_ETHERNET;
367       ni.mtu = 1500;
368       setIndexName(ni.ifname, "nas", num);
369       //sprintf(ni.ifname, "nas_%d", num);
370       err=ioctl (sock, BR2684_DEL, &ni);
371     } else {
372       syslog(LOG_ERR,"err: strange interface number %d", num );
373     }
374   }
375   return 0;
376 }
377
378
379 int vc_match(struct be_vc *vc, struct be_msg *msg)
380 {
381   if(vc == NULL) return 0;
382
383   if( vc->pvc.sap_addr.vpi == msg->pvc.sap_addr.vpi &&
384       vc->pvc.sap_addr.vci == msg->pvc.sap_addr.vci &&
385       vc->nas_idx          == msg->nas_idx
386       ) return 1;
387
388   return 0;
389 }
390
391
392 void do_delete(int cli_fd, struct be_msg *rmsg, struct ucred *cli_cred)
393 {
394   static struct be_vc placeholder, *bookmark = NULL;
395   static struct be_group *group = NULL, *prev_group = &group_head;
396   static pid_t curr_cli_pid;
397
398   struct be_vc *prev = NULL, *match = NULL, *new_next, *doomed;
399   struct be_msg smsg;
400   int search_done = 0;
401
402   /* New client instance means that we reset the current bookmark.
403    */
404   if(curr_cli_pid != cli_cred->pid) {
405     bookmark = NULL;
406     curr_cli_pid = cli_cred->pid;
407   }
408
409   if(bookmark == NULL || (vc_match(bookmark->next,rmsg) == 0)) {
410
411     /* No current bookmark, or the VC after the bookmark doesn't match
412        the VC we want to delete. Try to find the VC somewhere.
413     */
414
415     for(group = &group_head; group != NULL ; group = group->next) {
416       for(match = group->head; match != NULL; match = match->next) {
417         if((search_done = vc_match(match,rmsg))) break;
418         prev = match;
419       }
420       if(search_done) break;
421       prev_group = group;
422     }
423
424     if(!match) {
425       
426     /* VC not found, invalidate the bookmark, send fail message and return.
427      */
428
429       bookmark     = NULL;
430       smsg.msgtype = VC_NOT_FOUND;
431       if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
432         do_error(LOG_ERR,"do_delete couldn't send VC_NOT_FOUND response: %s",strerror(errno));
433       
434       return;
435     }
436  
437     /* Wrong credentials, also no dice.
438      */
439     if(match->uid != cli_cred->uid) {
440       
441       smsg.msgtype = NOT_OWNER;
442       smsg.uid     = bookmark->next->uid;
443       
444       if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
445         do_error(LOG_ERR,"do_delete couldn't send NOT_OWNER response: %s", strerror(errno));
446       return;
447     }
448
449     if(match == group->head) {
450
451       /* VC to be deleted is at the beginning of the group list. Set the bookmark
452          to our static placeholder, update its next member, and move the group head
453          to the next VC in the list.
454       */
455
456       if(match->next == NULL) {
457
458         /* Special case: if only one VC remains in the list, free the group if
459            we allocated it.
460         */
461         
462         if(group == &group_head) {
463           group->head = NULL;
464         } else {
465           prev_group->next = group->next;
466           free(group);
467           memstat.group_frees++;
468         }
469       }
470
471       bookmark       = &placeholder;
472       group->head    = match->next;
473       bookmark->next = match->next;
474       
475     } else if(match->next == NULL) {
476       
477       /* VC to be deleted is at the end of the list. Invalidate the bookmark
478          so we don't bother picking up where we left off next time. Also, update
479          the new last item in the list (prev) so that its next member points to NULL.
480       */
481       
482       bookmark   = NULL;
483       prev->next = NULL;
484       
485     } else {
486
487       /* VC to be deleted is somewhere in the middle of the list. Set the bookmark
488          to the previous VC, and set that VC's next member to the VC following the
489          one we'll be deleting.
490        */
491
492       bookmark       = prev;
493       bookmark->next = match->next;
494     }
495     
496     /* In all cases, close the socket related to the VC we want to delete,
497        free the memory, increment our vc_frees counter and send the OK message
498        to the client.
499     */
500
501     // brcm
502     delete_br(match->nas_idx);
503
504     close(match->sock);
505     free(match);
506     memstat.vc_frees++;
507
508     smsg.msgtype = OK;
509     if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
510       do_error(LOG_ERR,"no bookmark: do_delete couldn't send OK response: %s",strerror(errno));
511       
512    
513   } else { /* The bookmark is usable because its next member matches
514               the VC we want to delete.
515            */
516
517     if(bookmark->next->uid != cli_cred->uid) {
518
519     /* Wrong credentials, no dice.
520      */
521       
522       smsg.msgtype = NOT_OWNER;
523       smsg.uid     = bookmark->next->uid;
524
525       if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
526         do_error(LOG_ERR,"using bookmark: do_delete couldn't send NOT_OWNER response: %s",strerror(errno));
527
528       return;
529     }
530     
531     /* Remember the VC after the one we're going to delete.
532      */
533     new_next = bookmark->next->next;
534
535     if(bookmark->next == group->head) {
536
537       /* If we're at the beginning of the list, there are two special cases.
538        */
539
540       if(group->head->next == NULL) {
541
542         /* If only one VC remains in the list, free the group structure
543            (if we allocated it) and invalidate the bookmark.
544          */
545
546         doomed = group->head;
547
548         /* Don't free the global group list head!
549          */
550         if(group == &group_head) {
551           group->head = NULL;
552         } else {
553           prev_group->next = group->next;
554           free(group);
555           memstat.group_frees++;
556         }
557
558         bookmark = NULL;
559
560       } else {
561
562         /* If there is more than one VC in the list, we update the group head,
563            AND update the bookmark.
564         */
565
566         doomed         = bookmark->next;
567         group->head    = new_next;
568         bookmark->next = new_next;
569       }
570       
571     } else if(new_next == NULL) {
572
573       /* If the VC to be deleted is the last one, we set the bookmark VC's next pointer
574          to NULL, and then invalidate the bookmark.
575        */
576       
577       doomed         = bookmark->next;
578       bookmark->next = NULL;
579       bookmark       = NULL;
580       
581     } else {
582      
583       /* If the VC to be deleted is somewhere in the middle, then all we do is update
584          the bookmark and do the usual VC delete actions.
585       */
586       
587       doomed         = bookmark->next; 
588       bookmark->next = new_next;
589       
590     }
591
592     // brcm
593     delete_br(doomed->nas_idx);
594
595     close(doomed->sock);
596     free(doomed);
597     memstat.vc_frees++;
598
599     smsg.msgtype = OK;
600     if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
601       do_error(LOG_ERR,"do_delete couldn't send OK response: %s",strerror(errno));
602   }
603 }
604
605
606 void do_delete_group(int cli_fd, char *name, struct ucred *cli_cred)
607 {
608   struct be_group *group, *prev_group = NULL;
609   struct be_vc *curr,*doomed;
610   struct be_msg smsg;
611
612   smsg.msgtype = GROUP_NOT_FOUND;
613
614   for(group = &group_head; group != NULL; group = group->next) {
615     if(!strncmp(name,group->name,MAX_GROUPNAME_LEN))
616       break;
617     prev_group = group;
618   }
619
620   if(group) {
621     curr = group->head; 
622     while(curr != NULL) {
623       doomed = curr;
624       curr = curr->next;
625
626       // brcm
627       delete_br(doomed->nas_idx);
628
629       close(doomed->sock);
630       free(doomed);
631       memstat.vc_frees++;
632     }
633
634     prev_group->next = group->next;
635     free(group);
636     memstat.group_frees++;
637     smsg.msgtype = OK;
638   }
639
640   if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
641     do_error(LOG_ERR,"do_delete_group() couldn't send response: %s",strerror(errno));
642 }
643
644
645 void do_list_group(int cli_fd, struct be_msg *rmsg)
646 {
647   struct be_group *group;
648   struct be_vc *curr;
649   struct be_msg smsg;
650
651   smsg.msgtype = GROUP_NOT_FOUND;
652
653   for(group = &group_head; group != NULL; group = group->next)
654     if(!strncmp(rmsg->name,group->name,MAX_GROUPNAME_LEN))
655       break;
656
657   if(group) {
658     for(curr = group->head; curr != NULL; curr = curr->next) {
659
660       smsg.msgtype =  OK;
661       smsg.nas_idx = curr->nas_idx;
662       smsg.uid     = curr->uid;
663       memcpy(&smsg.pvc, &curr->pvc, sizeof(struct sockaddr_atmpvc));
664       memcpy(&smsg.name, &group->name, MAX_GROUPNAME_LEN);
665       if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
666         do_error(LOG_ERR,"do_list_group() couldn't send OK message: %s",strerror(errno));
667     }
668
669     smsg.msgtype = LIST_END;
670   }
671
672   if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
673     do_error(LOG_ERR,"do_list_group() couldn't send LIST_END message: %s",strerror(errno));
674 }
675
676
677 void do_list_all(int cli_fd, struct be_msg *rmsg)
678 {
679   struct be_group *group = NULL;
680   struct be_vc *curr;
681   struct be_msg smsg;
682
683   for(group = &group_head; group != NULL; group = group->next) {
684
685     for(curr = group->head; curr != NULL; curr = curr->next) {
686
687       smsg.msgtype = OK; 
688       smsg.nas_idx = curr->nas_idx;
689       smsg.uid     = curr->uid;
690       memcpy(&smsg.pvc, &curr->pvc, sizeof(struct sockaddr_atmpvc));
691       memcpy(&smsg.name, group->name, MAX_GROUPNAME_LEN);
692       // brcm begin
693       smsg.mode = curr->mode;
694       smsg.vlan_id = curr->vlan_id;
695       // brcm end
696       if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
697         do_error(LOG_ERR,"do_list_all() couldn't send VC info: %s",strerror(errno));
698     }
699
700   }
701
702   if(smsg.msgtype == OK) 
703     smsg.msgtype = LIST_END;
704   else
705     smsg.msgtype = GROUP_NOT_FOUND;
706
707   if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
708     do_error(LOG_ERR,"do_list_all() couldn't send LIST_END message: %s",strerror(errno));
709 }
710
711 #ifdef BUILD_STATIC
712 int pvc2684d_main (int argc, char **argv)
713 #else
714 int main (int argc, char **argv)
715 #endif
716 {
717   int test_fd, listen_fd, cli_fd;
718   socklen_t  cliaddr_len;
719   struct sockaddr_un test_addr, listen_addr, cli_addr;
720   const int on = 1;
721   int nbytes;
722   struct ucred cli_cred;
723   int ucred_len = sizeof(cli_cred);
724   struct be_msg smsg, rmsg;
725   struct stat listen_stat;
726
727   openlog("pvc2684d",LOG_PERROR, LOG_DAEMON);
728
729   bzero(group_head.name,MAX_GROUPNAME_LEN);
730   group_head.head = NULL;
731   group_head.next = NULL;
732
733   bzero(&test_addr, sizeof(test_addr));
734   test_addr.sun_family = AF_LOCAL;
735   strncpy(test_addr.sun_path, BRPVC_SOCKPATH, sizeof(test_addr.sun_path) -1);
736   memcpy(&listen_addr, &test_addr, sizeof(test_addr));
737
738   if( (test_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 
739     do_error(LOG_ERR,"Couldn't create initial socket: %s",strerror(errno));
740
741   /* Check for already running daemon  */
742
743   if(connect(test_fd, (struct sockaddr *) &test_addr, sizeof(test_addr))) {
744     if(errno == ECONNREFUSED)
745       unlink(BRPVC_SOCKPATH);
746   }
747   close(test_fd);
748
749   if( (listen_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
750     do_error(LOG_ERR,"Couldn't create server socket: %s",strerror(errno));
751
752   if( bind(listen_fd, (struct sockaddr *) &listen_addr, SUN_LEN(&listen_addr)) ) {
753     do_error(LOG_WARNING,"Another b2684d is running");
754     exit(-1);
755   }
756   
757   
758   if(stat(BRPVC_SOCKPATH, &listen_stat))
759     do_error(LOG_ERR,"Can't fstat listen socket: %s",strerror(errno));
760
761   if(chmod(BRPVC_SOCKPATH, listen_stat.st_mode | S_IWOTH))
762     do_error(LOG_ERR,"Can't fchmod listen socket: %s",strerror(errno));
763
764   if( listen(listen_fd, 5) )
765     do_error(LOG_ERR,"listen() on server socket failed: %s",strerror(errno));
766   
767   while(1) {
768     cliaddr_len = sizeof(cli_addr);
769     if((cli_fd = accept(listen_fd, (struct sockaddr *) &cli_addr, &cliaddr_len)) < 0) {
770       if(errno == EINTR)
771         continue;
772       else
773         do_error(LOG_ERR,"accept() on server socket failed: %s",strerror(errno));
774     }
775     if( setsockopt(cli_fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0 )
776       do_error(LOG_ERR,"setsockopt() on client socket failed: %s",strerror(errno));
777     
778     while((nbytes = recv(cli_fd, &rmsg, sizeof(rmsg), 0)) > 0) {
779       switch (rmsg.msgtype) {
780         
781       case HELLO:
782         
783         if ( getsockopt(cli_fd, SOL_SOCKET, SO_PEERCRED, &cli_cred, &ucred_len) < 0 )
784           do_error(LOG_ERR,"getsockopt() for credentials failed: %s",strerror(errno));
785         
786         smsg.msgtype = OK;
787         if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
788           do_error(LOG_ERR,"Couldn't send OK message to new client: %s",strerror(errno)); 
789
790         break;
791       
792       case ADD:
793
794         do_add(cli_fd,&rmsg,&cli_cred);
795         break;
796       
797       case DELETE:
798
799         do_delete(cli_fd,&rmsg,&cli_cred);
800         break;
801       
802       case DELETE_GROUP:
803
804         do_delete_group(cli_fd,rmsg.name,&cli_cred);
805         break;
806       
807       case LIST_GROUP:
808          
809         do_list_group(cli_fd,&rmsg);
810         break;
811       
812       case LIST_ALL:
813
814         do_list_all(cli_fd,&rmsg);
815         break;
816
817       case MEM_STATS:
818         
819         if( send(cli_fd, &memstat, sizeof(memstat), 0) < 0 )
820           do_error(LOG_ERR,"Couldn't send MEM_STAT message: %s",strerror(errno)); 
821         break;
822       
823       default:
824         smsg.msgtype = UNKNOWN_CMD;
825         if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
826           do_error(LOG_ERR,"Couldn't send UNKNOWN_COMMAND message: %s",strerror(errno)); 
827       }
828     }
829     close(cli_fd);
830   }
831 }