http://downloads.netgear.com/files/GPL/GPL_Source_V361j_DM111PSP_series_consumer_rele...
[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
215   //brcm begin: static pointers of prev_vc,group has problems when delete is called in between adds
216   //  static struct be_group *group = &group_head;
217   //  static struct be_vc *prev_vc = NULL;
218   struct be_group *group = &group_head;
219   struct be_vc *prev_vc = NULL;
220   //brcm end
221   static char curr_groupname[MAX_GROUPNAME_LEN] = {};
222   static pid_t curr_cli_pid = 0;
223
224   struct be_group *last_group = NULL, *new_group;
225   struct be_vc *new_vc;
226   struct be_msg smsg;
227   int sock;
228
229   /* New client instance means that we reset the current working group.
230    */
231   if(curr_cli_pid != cli_cred->pid) {
232     curr_groupname[0] = '\0';
233     group = &group_head;
234     curr_cli_pid = cli_cred->pid;
235   }
236
237 // brcm
238   if(create_br(rmsg->nas_idx, rmsg->mode) == 0) {
239 //  if(create_br(rmsg->nas_idx) == 0) {
240
241     smsg.msgtype = INTERFACE_FAILED;
242     if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
243       do_error(LOG_WARNING,"do_add() couldn't send interface creation failure message.");
244     return;
245   }
246
247 // brcm
248   if( (sock = assign_vcc(rmsg->pvc, rmsg->nas_idx, rmsg->encap, 8192, rmsg->proto_filter, rmsg->mode, \
249           rmsg->vlan_id)) < 0) {
250 //  if( (sock = assign_vcc(rmsg->pvc, rmsg->nas_idx, BR2684_ENCAPS_LLC, 8192)) < 0) {
251     
252     smsg.msgtype = SOCK_FAILED;
253     if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
254       do_error(LOG_WARNING,"do_add() couldn't send socket creation failure message.");
255     return;
256   }
257
258   /* See if this group is different from the last one. If isn't, we simply pick up where
259      we left off last time with the group and vc pointers stored in static variables.
260      This is more efficient for multiple adds, because we always want go to the end of 
261      the current group's VC list.
262   */
263   if( strncmp(rmsg->name,curr_groupname,MAX_GROUPNAME_LEN) ) {
264     
265     /* This groupname is different from the last one. Remember it for next time.
266      */
267
268     strncpy(curr_groupname,rmsg->name,MAX_GROUPNAME_LEN); 
269
270     /* Does this group exist?  
271      */
272     for(group = &group_head; group != NULL; group = group->next) {
273       last_group = group;
274       if(!strncmp(rmsg->name,group->name,MAX_GROUPNAME_LEN)) 
275         break;
276     }
277
278     if(!group) {
279
280       /* Nope.  Create a new group.
281        */
282       if(! (new_group = (struct be_group *)malloc(sizeof(struct be_group))) ) {
283         do_error(LOG_WARNING,"can't allocate memory for new group %s", rmsg->name);
284         
285         close(sock);
286         smsg.msgtype = NOMEM;
287         if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
288           do_error(LOG_WARNING,"do_add() couldn't send malloc failure message for new group.");
289         return;
290       }
291   
292       memstat.group_mallocs++;
293
294       last_group->next      = new_group;
295       new_group->head       = NULL;
296       new_group->next       = NULL;
297       strncpy(new_group->name,rmsg->name,MAX_GROUPNAME_LEN);
298       
299       /* set prev_vc to the VC list head.
300        */
301       group = new_group;
302       prev_vc = group->head;
303     } else
304
305       /* Ratchet to the end of an existing group VC list.
306        */
307       for(prev_vc = group->head; prev_vc->next != NULL; prev_vc=prev_vc->next);
308   }
309
310   /* Create the new VC
311    */
312   if(! (new_vc = (struct be_vc *)malloc(sizeof(struct be_vc))) ) {
313     do_error(LOG_WARNING,"can't allocate memory for new vc %d/%d on nas%d\n",
314              rmsg->pvc.sap_addr.vpi,
315              rmsg->pvc.sap_addr.vci,
316              rmsg->nas_idx
317              );
318
319     close(sock);
320     smsg.msgtype = NOMEM;
321     if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
322       do_error(LOG_WARNING,"do_add() couldn't send malloc failure message for new VC.");
323     return;
324   }
325   
326   memstat.vc_mallocs++;
327   
328   new_vc->nas_idx  = rmsg->nas_idx;
329   memcpy(&new_vc->pvc, &rmsg->pvc, sizeof(struct sockaddr_atmpvc));
330   new_vc->sock    = sock;
331   new_vc->uid     = cli_cred->uid;
332   new_vc->vlan_id = rmsg->vlan_id;
333   new_vc->next    = NULL;
334   
335   /* Add the new VC to the end of the list and remember the
336      new end for next time. This "if" block is neccessary because
337      we cannot initialize prev_vc with the address of group_head.pvc,
338      which is non-constant. My intent is to keep most of the state 
339      variables local to this function.
340   */
341   if(!group->head) {
342     group->head = new_vc;
343   }
344   else {
345     for(prev_vc = group->head; prev_vc->next != NULL; prev_vc=prev_vc->next) ;
346
347     if(prev_vc) {
348     prev_vc->next = new_vc;
349     }
350   }
351   //brcm this has a problem if the VCC in the list is deleted
352   //prev_vc       = new_vc;
353   
354   smsg.msgtype = OK;
355   if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
356     do_error(LOG_ERR,"do_add couldn't send OK response: %s",strerror(errno));           
357 }
358
359 // brcm
360 int delete_br(int num)
361 //int delete_br(char *nstr)
362 {
363 //  int num, err;
364   int err;
365   int sock;
366
367   sock = socket(PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
368   if (sock<0) {
369     syslog(LOG_ERR, "socket creation failed: %s",strerror(errno));
370   } else {
371     /* create the device with ioctl: */
372     //num=atoi(nstr);
373     if( num>=0 && num<1234567890){
374       struct atm_newif_br2684 ni;
375       ni.backend_num = ATM_BACKEND_BR2684;
376       ni.media = BR2684_MEDIA_ETHERNET;
377       ni.mtu = 1500;
378       setIndexName(ni.ifname, "nas", num);
379       //sprintf(ni.ifname, "nas_%d", num);
380       err=ioctl (sock, BR2684_DEL, &ni);
381     } else {
382       syslog(LOG_ERR,"err: strange interface number %d", num );
383     }
384   }
385   return 0;
386 }
387
388
389 int vc_match(struct be_vc *vc, struct be_msg *msg)
390 {
391   if(vc == NULL) return 0;
392
393   if( vc->pvc.sap_addr.vpi == msg->pvc.sap_addr.vpi &&
394       vc->pvc.sap_addr.vci == msg->pvc.sap_addr.vci &&
395       vc->nas_idx          == msg->nas_idx
396       ) return 1;
397
398   return 0;
399 }
400
401
402 void do_delete(int cli_fd, struct be_msg *rmsg, struct ucred *cli_cred)
403 {
404   static struct be_vc placeholder, *bookmark = NULL;
405   static struct be_group *group = NULL, *prev_group = &group_head;
406   static pid_t curr_cli_pid;
407
408   struct be_vc *prev = NULL, *match = NULL, *new_next, *doomed;
409   struct be_msg smsg;
410   int search_done = 0;
411
412   /* New client instance means that we reset the current bookmark.
413    */
414   if(curr_cli_pid != cli_cred->pid) {
415     bookmark = NULL;
416     curr_cli_pid = cli_cred->pid;
417   }
418
419   if(bookmark == NULL || (vc_match(bookmark->next,rmsg) == 0)) {
420
421     /* No current bookmark, or the VC after the bookmark doesn't match
422        the VC we want to delete. Try to find the VC somewhere.
423     */
424
425     for(group = &group_head; group != NULL ; group = group->next) {
426       for(match = group->head; match != NULL; match = match->next) {
427         if((search_done = vc_match(match,rmsg))) break;
428         prev = match;
429       }
430       if(search_done) break;
431       prev_group = group;
432     }
433
434     if(!match) {
435       
436     /* VC not found, invalidate the bookmark, send fail message and return.
437      */
438
439       bookmark     = NULL;
440       smsg.msgtype = VC_NOT_FOUND;
441       if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
442         do_error(LOG_ERR,"do_delete couldn't send VC_NOT_FOUND response: %s",strerror(errno));
443       
444       return;
445     }
446  
447     /* Wrong credentials, also no dice.
448      */
449     if(match->uid != cli_cred->uid) {
450       
451       smsg.msgtype = NOT_OWNER;
452       smsg.uid     = bookmark->next->uid;
453       
454       if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
455         do_error(LOG_ERR,"do_delete couldn't send NOT_OWNER response: %s", strerror(errno));
456       return;
457     }
458
459     if(match == group->head) {
460
461       /* VC to be deleted is at the beginning of the group list. Set the bookmark
462          to our static placeholder, update its next member, and move the group head
463          to the next VC in the list.
464       */
465
466       if(match->next == NULL) {
467
468         /* Special case: if only one VC remains in the list, free the group if
469            we allocated it.
470         */
471         
472         if(group == &group_head) {
473           group->head = NULL;
474         } else {
475           prev_group->next = group->next;
476           free(group);
477           memstat.group_frees++;
478         }
479       }
480
481       bookmark       = &placeholder;
482       group->head    = match->next;
483       bookmark->next = match->next;
484       
485     } else if(match->next == NULL) {
486       
487       /* VC to be deleted is at the end of the list. Invalidate the bookmark
488          so we don't bother picking up where we left off next time. Also, update
489          the new last item in the list (prev) so that its next member points to NULL.
490       */
491       
492       bookmark   = NULL;
493       prev->next = NULL;
494       
495     } else {
496
497       /* VC to be deleted is somewhere in the middle of the list. Set the bookmark
498          to the previous VC, and set that VC's next member to the VC following the
499          one we'll be deleting.
500        */
501
502       bookmark       = prev;
503       bookmark->next = match->next;
504     }
505     
506     /* In all cases, close the socket related to the VC we want to delete,
507        free the memory, increment our vc_frees counter and send the OK message
508        to the client.
509     */
510
511     // brcm
512     delete_br(match->nas_idx);
513
514     close(match->sock);
515     free(match);
516     memstat.vc_frees++;
517
518     smsg.msgtype = OK;
519     if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
520       do_error(LOG_ERR,"no bookmark: do_delete couldn't send OK response: %s",strerror(errno));
521       
522    
523   } else { /* The bookmark is usable because its next member matches
524               the VC we want to delete.
525            */
526
527     if(bookmark->next->uid != cli_cred->uid) {
528
529     /* Wrong credentials, no dice.
530      */
531       
532       smsg.msgtype = NOT_OWNER;
533       smsg.uid     = bookmark->next->uid;
534
535       if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
536         do_error(LOG_ERR,"using bookmark: do_delete couldn't send NOT_OWNER response: %s",strerror(errno));
537
538       return;
539     }
540     
541     /* Remember the VC after the one we're going to delete.
542      */
543     new_next = bookmark->next->next;
544
545     if(bookmark->next == group->head) {
546
547       /* If we're at the beginning of the list, there are two special cases.
548        */
549
550       if(group->head->next == NULL) {
551
552         /* If only one VC remains in the list, free the group structure
553            (if we allocated it) and invalidate the bookmark.
554          */
555
556         doomed = group->head;
557
558         /* Don't free the global group list head!
559          */
560         if(group == &group_head) {
561           group->head = NULL;
562         } else {
563           prev_group->next = group->next;
564           free(group);
565           memstat.group_frees++;
566         }
567
568         bookmark = NULL;
569
570       } else {
571
572         /* If there is more than one VC in the list, we update the group head,
573            AND update the bookmark.
574         */
575
576         doomed         = bookmark->next;
577         group->head    = new_next;
578         bookmark->next = new_next;
579       }
580       
581     } else if(new_next == NULL) {
582
583       /* If the VC to be deleted is the last one, we set the bookmark VC's next pointer
584          to NULL, and then invalidate the bookmark.
585        */
586       
587       doomed         = bookmark->next;
588       bookmark->next = NULL;
589       bookmark       = NULL;
590       
591     } else {
592      
593       /* If the VC to be deleted is somewhere in the middle, then all we do is update
594          the bookmark and do the usual VC delete actions.
595       */
596       
597       doomed         = bookmark->next; 
598       bookmark->next = new_next;
599       
600     }
601
602     // brcm
603     delete_br(doomed->nas_idx);
604
605     close(doomed->sock);
606     free(doomed);
607     memstat.vc_frees++;
608
609     smsg.msgtype = OK;
610     if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
611       do_error(LOG_ERR,"do_delete couldn't send OK response: %s",strerror(errno));
612   }
613 }
614
615
616 void do_delete_group(int cli_fd, char *name, struct ucred *cli_cred)
617 {
618   struct be_group *group, *prev_group = NULL;
619   struct be_vc *curr,*doomed;
620   struct be_msg smsg;
621
622   smsg.msgtype = GROUP_NOT_FOUND;
623
624   for(group = &group_head; group != NULL; group = group->next) {
625     if(!strncmp(name,group->name,MAX_GROUPNAME_LEN))
626       break;
627     prev_group = group;
628   }
629
630   if(group) {
631     curr = group->head; 
632     while(curr != NULL) {
633       doomed = curr;
634       curr = curr->next;
635
636       // brcm
637       delete_br(doomed->nas_idx);
638
639       close(doomed->sock);
640       free(doomed);
641       memstat.vc_frees++;
642     }
643
644     prev_group->next = group->next;
645     free(group);
646     memstat.group_frees++;
647     smsg.msgtype = OK;
648   }
649
650   if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
651     do_error(LOG_ERR,"do_delete_group() couldn't send response: %s",strerror(errno));
652 }
653
654
655 void do_list_group(int cli_fd, struct be_msg *rmsg)
656 {
657   struct be_group *group;
658   struct be_vc *curr;
659   struct be_msg smsg;
660
661   smsg.msgtype = GROUP_NOT_FOUND;
662
663   for(group = &group_head; group != NULL; group = group->next)
664     if(!strncmp(rmsg->name,group->name,MAX_GROUPNAME_LEN))
665       break;
666
667   if(group) {
668     for(curr = group->head; curr != NULL; curr = curr->next) {
669
670       smsg.msgtype =  OK;
671       smsg.nas_idx = curr->nas_idx;
672       smsg.uid     = curr->uid;
673       memcpy(&smsg.pvc, &curr->pvc, sizeof(struct sockaddr_atmpvc));
674       memcpy(&smsg.name, &group->name, MAX_GROUPNAME_LEN);
675       if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
676         do_error(LOG_ERR,"do_list_group() couldn't send OK message: %s",strerror(errno));
677     }
678
679     smsg.msgtype = LIST_END;
680   }
681
682   if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
683     do_error(LOG_ERR,"do_list_group() couldn't send LIST_END message: %s",strerror(errno));
684 }
685
686
687 void do_list_all(int cli_fd, struct be_msg *rmsg)
688 {
689   struct be_group *group = NULL;
690   struct be_vc *curr;
691   struct be_msg smsg;
692
693   for(group = &group_head; group != NULL; group = group->next) {
694
695     for(curr = group->head; curr != NULL; curr = curr->next) {
696
697       smsg.msgtype = OK; 
698       smsg.nas_idx = curr->nas_idx;
699       smsg.uid     = curr->uid;
700       memcpy(&smsg.pvc, &curr->pvc, sizeof(struct sockaddr_atmpvc));
701       memcpy(&smsg.name, group->name, MAX_GROUPNAME_LEN);
702       // brcm begin
703       smsg.mode = curr->mode;
704       smsg.vlan_id = curr->vlan_id;
705       // brcm end
706       if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
707         do_error(LOG_ERR,"do_list_all() couldn't send VC info: %s",strerror(errno));
708     }
709
710   }
711
712   if(smsg.msgtype == OK) 
713     smsg.msgtype = LIST_END;
714   else
715     smsg.msgtype = GROUP_NOT_FOUND;
716
717   if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
718     do_error(LOG_ERR,"do_list_all() couldn't send LIST_END message: %s",strerror(errno));
719 }
720
721 #ifdef BUILD_STATIC
722 int pvc2684d_main (int argc, char **argv)
723 #else
724 int main (int argc, char **argv)
725 #endif
726 {
727   int test_fd, listen_fd, cli_fd;
728   socklen_t  cliaddr_len;
729   struct sockaddr_un test_addr, listen_addr, cli_addr;
730   const int on = 1;
731   int nbytes;
732   struct ucred cli_cred;
733   int ucred_len = sizeof(cli_cred);
734   struct be_msg smsg, rmsg;
735   struct stat listen_stat;
736
737   openlog("pvc2684d",LOG_PERROR, LOG_DAEMON);
738
739   bzero(group_head.name,MAX_GROUPNAME_LEN);
740   group_head.head = NULL;
741   group_head.next = NULL;
742
743   bzero(&test_addr, sizeof(test_addr));
744   test_addr.sun_family = AF_LOCAL;
745   strncpy(test_addr.sun_path, BRPVC_SOCKPATH, sizeof(test_addr.sun_path) -1);
746   memcpy(&listen_addr, &test_addr, sizeof(test_addr));
747
748   if( (test_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 
749     do_error(LOG_ERR,"Couldn't create initial socket: %s",strerror(errno));
750
751   /* Check for already running daemon  */
752
753   if(connect(test_fd, (struct sockaddr *) &test_addr, sizeof(test_addr))) {
754     if(errno == ECONNREFUSED)
755       unlink(BRPVC_SOCKPATH);
756   }
757   close(test_fd);
758
759   if( (listen_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
760     do_error(LOG_ERR,"Couldn't create server socket: %s",strerror(errno));
761
762   if( bind(listen_fd, (struct sockaddr *) &listen_addr, SUN_LEN(&listen_addr)) ) {
763     do_error(LOG_WARNING,"Another b2684d is running");
764     exit(-1);
765   }
766   
767   
768   if(stat(BRPVC_SOCKPATH, &listen_stat))
769     do_error(LOG_ERR,"Can't fstat listen socket: %s",strerror(errno));
770
771   if(chmod(BRPVC_SOCKPATH, listen_stat.st_mode | S_IWOTH))
772     do_error(LOG_ERR,"Can't fchmod listen socket: %s",strerror(errno));
773
774   if( listen(listen_fd, 5) )
775     do_error(LOG_ERR,"listen() on server socket failed: %s",strerror(errno));
776   
777   while(1) {
778     cliaddr_len = sizeof(cli_addr);
779     if((cli_fd = accept(listen_fd, (struct sockaddr *) &cli_addr, &cliaddr_len)) < 0) {
780       if(errno == EINTR)
781         continue;
782       else
783         do_error(LOG_ERR,"accept() on server socket failed: %s",strerror(errno));
784     }
785     if( setsockopt(cli_fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0 )
786       do_error(LOG_ERR,"setsockopt() on client socket failed: %s",strerror(errno));
787     
788     while((nbytes = recv(cli_fd, &rmsg, sizeof(rmsg), 0)) > 0) {
789       switch (rmsg.msgtype) {
790         
791       case HELLO:
792         
793         if ( getsockopt(cli_fd, SOL_SOCKET, SO_PEERCRED, &cli_cred, &ucred_len) < 0 )
794           do_error(LOG_ERR,"getsockopt() for credentials failed: %s",strerror(errno));
795         
796         smsg.msgtype = OK;
797         if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
798           do_error(LOG_ERR,"Couldn't send OK message to new client: %s",strerror(errno)); 
799
800         break;
801       
802       case ADD:
803
804         do_add(cli_fd,&rmsg,&cli_cred);
805         break;
806       
807       case DELETE:
808
809         do_delete(cli_fd,&rmsg,&cli_cred);
810         break;
811       
812       case DELETE_GROUP:
813
814         do_delete_group(cli_fd,rmsg.name,&cli_cred);
815         break;
816       
817       case LIST_GROUP:
818          
819         do_list_group(cli_fd,&rmsg);
820         break;
821       
822       case LIST_ALL:
823
824         do_list_all(cli_fd,&rmsg);
825         break;
826
827       case MEM_STATS:
828         
829         if( send(cli_fd, &memstat, sizeof(memstat), 0) < 0 )
830           do_error(LOG_ERR,"Couldn't send MEM_STAT message: %s",strerror(errno)); 
831         break;
832       
833       default:
834         smsg.msgtype = UNKNOWN_CMD;
835         if( send(cli_fd, &smsg, sizeof(smsg), 0) < 0 )
836           do_error(LOG_ERR,"Couldn't send UNKNOWN_COMMAND message: %s",strerror(errno)); 
837       }
838     }
839     close(cli_fd);
840   }
841 }