br2684ctl...
[ipfire-2.x.git] / src / br2684ctl / br2684ctl.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <errno.h>
5 #include <sys/ioctl.h>
6 #include <string.h>
7 #include <syslog.h>
8 #include <atm.h>
9 #include <linux/atmdev.h>
10 #include <linux/atmbr2684.h>
11
12 /* Written by Marcell GAL <cell@sch.bme.hu> to make use of the */
13 /* ioctls defined in the br2684... kernel patch */
14 /* Compile with cc -o br2684ctl br2684ctl.c -latm */
15
16 /*
17   Modified feb 2001 by Stephen Aaskov (saa@lasat.com)
18   - Added daemonization code
19   - Added syslog
20   
21   TODO: Delete interfaces after exit?
22 */
23
24
25 #define LOG_NAME "RFC1483/2684 bridge"
26 #define LOG_OPTION     LOG_PERROR
27 #define LOG_FACILITY   LOG_LOCAL0
28
29
30 int lastsock, lastitf;
31
32
33 void fatal(const char *str, int i)
34 {
35   syslog (LOG_ERR,"Fatal: %s",str);
36   exit(-2);
37 };
38
39
40 void exitFunc(void)
41 {
42   syslog (LOG_PID,"Daemon terminated\n");       
43 }
44
45
46 int create_pidfile(int num)
47 {
48   FILE *pidfile = NULL;
49   char name[32];
50
51   if (num < 0) return -1;
52
53   snprintf(name, 20, "/var/run/nas%d.pid", num);
54   pidfile = fopen(name, "w");
55   if (pidfile == NULL) return -1;
56   fprintf(pidfile, "%d", getpid());
57   fclose(pidfile);
58
59   return 0;
60 }
61
62 int create_br(char *nstr)
63 {
64   int num, err;
65   
66   if(lastsock<0) {
67     lastsock = socket(PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
68   }
69   if (lastsock<0) {
70     syslog(LOG_ERR, "socket creation failed: %s",strerror(errno));
71   } else {
72     /* create the device with ioctl: */
73     num=atoi(nstr);
74     if( num>=0 && num<1234567890){
75       struct atm_newif_br2684 ni;
76       ni.backend_num = ATM_BACKEND_BR2684;
77       ni.media = BR2684_MEDIA_ETHERNET;
78       ni.mtu = 1500;
79       sprintf(ni.ifname, "nas%d", num);
80       err=ioctl (lastsock, ATM_NEWBACKENDIF, &ni);
81   
82       if (err == 0)
83         syslog(LOG_INFO, "Interface \"%s\" created sucessfully\n",ni.ifname);
84       else
85         syslog(LOG_INFO, "Interface \"%s\" could not be created, reason: %s\n",
86                ni.ifname,
87                strerror(errno));
88       lastitf=num;      /* even if we didn't create, because existed, assign_vcc wil want to know it! */
89     } else {
90       syslog(LOG_ERR,"err: strange interface number %d", num );
91     }
92   }
93   return 0;
94 }
95
96
97 int assign_vcc(char *astr, int encap, int bufsize, struct atm_qos qos)
98 {
99     int err;
100     struct sockaddr_atmpvc addr;
101     int fd;
102     struct atm_backend_br2684 be;
103
104     memset(&addr, 0, sizeof(addr));
105     err=text2atm(astr,(struct sockaddr *)(&addr), sizeof(addr), T2A_PVC);
106     if (err!=0)
107       syslog(LOG_ERR,"Could not parse ATM parameters (error=%d)\n",err);
108     
109 #if 0
110     addr.sap_family = AF_ATMPVC;
111     addr.sap_addr.itf = itf;
112     addr.sap_addr.vpi = 0;
113     addr.sap_addr.vci = vci;
114 #endif
115     syslog(LOG_INFO,"Communicating over ATM %d.%d.%d, encapsulation: %s\n", addr.sap_addr.itf,
116            addr.sap_addr.vpi,
117            addr.sap_addr.vci,
118            encap?"VC mux":"LLC");
119     
120     if ((fd = socket(PF_ATMPVC, SOCK_DGRAM, ATM_AAL5)) < 0)
121       syslog(LOG_ERR,"failed to create socket %d, reason: %s", errno,strerror(errno));
122     
123     if (qos.aal == 0) {
124       qos.aal                     = ATM_AAL5;
125       qos.txtp.traffic_class      = ATM_UBR;
126       qos.txtp.max_sdu            = 1524;
127       qos.txtp.pcr                = ATM_MAX_PCR;
128       qos.rxtp = qos.txtp;
129     }
130
131     if ( (err=setsockopt(fd,SOL_SOCKET,SO_SNDBUF, &bufsize ,sizeof(bufsize))) )
132       syslog(LOG_ERR,"setsockopt SO_SNDBUF: (%d) %s\n",err, strerror(err));
133     
134     if (setsockopt(fd, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0)
135       syslog(LOG_ERR,"setsockopt SO_ATMQOS %d", errno);
136
137     err = connect(fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_atmpvc));
138     
139     if (err < 0)
140       fatal("failed to connect on socket", err);
141     
142     /* attach the vcc to device: */
143     
144     be.backend_num = ATM_BACKEND_BR2684;
145     be.ifspec.method = BR2684_FIND_BYIFNAME;
146     sprintf(be.ifspec.spec.ifname, "nas%d", lastitf);
147     be.fcs_in = BR2684_FCSIN_NO;
148     be.fcs_out = BR2684_FCSOUT_NO;
149     be.fcs_auto = 0;
150     be.encaps = encap ? BR2684_ENCAPS_VC : BR2684_ENCAPS_LLC;
151     be.has_vpiid = 0;
152     be.send_padding = 0;
153     be.min_size = 0;
154     err=ioctl (fd, ATM_SETBACKEND, &be);
155     if (err == 0)
156       syslog (LOG_INFO,"Interface configured");
157     else {
158       syslog (LOG_ERR,"Could not configure interface:%s",strerror(errno));
159       exit(2);
160     }
161     return fd ;
162 }
163
164
165 void usage(char *s)
166 {
167   printf("usage: %s [-b] [[-c number] [-e 0|1] [-s sndbuf] [-q qos] [-a [itf.]vpi.vci]*]*\n", s);
168   exit(1);
169 }
170
171
172
173 int main (int argc, char **argv)
174 {
175   int c, background=0, encap=0, sndbuf=8192;
176   struct atm_qos reqqos;
177   int itfnum;
178   lastsock=-1;
179   lastitf=0;
180   
181   /* st qos to 0 */
182   memset(&reqqos, 0, sizeof(reqqos));
183
184   openlog (LOG_NAME,LOG_OPTION,LOG_FACILITY);
185   if (argc>1)
186     while ((c = getopt(argc, argv,"q:a:bc:e:s:?h")) !=EOF)
187       switch (c) {
188       case 'q':
189         printf ("optarg : %s",optarg);
190         if (text2qos(optarg,&reqqos,0)) fprintf(stderr,"QOS parameter invalid\n"); 
191         break;
192       case 'a':
193         assign_vcc(optarg, encap, sndbuf, reqqos);
194         break;
195       case 'b':
196         background=1;
197         break;
198       case 'c':
199         create_br(optarg);
200         itfnum = atoi(optarg);
201         break;
202       case 'e':
203         encap=(atoi(optarg));
204         if(encap<0){
205           syslog (LOG_ERR, "invalid encapsulation: %s:\n",optarg);
206           encap=0;
207         }
208         break;
209       case 's':
210         sndbuf=(atoi(optarg));
211         if(sndbuf<0){
212           syslog(LOG_ERR, "Invalid sndbuf: %s, using size of 8192 instead\n",optarg);
213           sndbuf=8192;
214         }
215         break;
216       case '?':
217       case 'h':
218       default:
219         usage(argv[0]);
220       }
221   else
222     usage(argv[0]);
223
224   if (argc != optind) usage(argv[0]);
225   
226   if(lastsock>=0) close(lastsock);
227   
228   if (background) {
229     pid_t pid;
230     
231     pid=fork();
232     if (pid < 0) {
233       fprintf(stderr,"Error detaching\n");
234       exit(2);
235     } else if (pid) 
236       exit(0); // This is the parent
237     
238     // Become a process group and session group leader
239     if (setsid()<0) {
240       fprintf (stderr,"Could not set process group\n");
241       exit(2);
242     }
243     
244     // Fork again to let process group leader exit
245     pid = fork();
246     if (pid < 0) {
247       fprintf(stderr,"Error detaching during second fork\n");
248       exit(2);
249     } else if (pid)
250       exit(0); // This is the parent
251     
252     // Now we're ready for buisness
253     chdir("/");            // Don't keep directories in use
254     close(0); close(1); close(2);  // Close stdin, -out and -error
255     /*
256       Note that this implementation does not keep an open 
257       stdout/err.
258       If we need them they can be opened now
259     */
260     
261   }
262   
263   create_pidfile(itfnum);
264
265   syslog (LOG_INFO, "RFC 1483/2684 bridge daemon started\n");   
266   atexit (exitFunc);
267   
268   while (1) sleep(30);  /* to keep the sockets... */
269   return 0;
270 }
271