6bd1b851c450ae61ba476377d236d522ff1a717b
[bcm963xx.git] / userapps / opensource / atm2684 / atm / lane / connect_bus.c
1 /*
2  * ATM connection wrapper
3  *
4  * $Id: connect_bus.c,v 1.1.1.1 2005/04/29 01:44:51 echo Exp $
5  *
6  */
7
8 /* System includes */
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <fcntl.h>
13 #include <sys/ioctl.h>
14 #include <assert.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18 #include <sys/types.h>
19 #include <errno.h>
20
21 /* Local includes */
22 #include "mem.h"
23 #include "lane.h"
24 #include "dump.h"
25 #include "load.h"
26 #include "connect.h"
27 #include "events.h"
28 #include "atm.h"
29
30 /* Type definitions */
31
32 /* Local function prototypes */
33 static void conn_init0(void);
34 static void conn_init1(void);
35 static void conn_dump(void);
36 static void conn_release(void);
37 static const char *dump_conn_type(ConnType_t type);
38
39 static int data_handler(const Event_t *event, void *funcdata);
40 static void conn_main(void);
41
42 /* Had to remove const qualifiers since not every
43  * function honored it. hessu@cs.tut.fi
44  */
45 static int join(Conn_t *conn);
46 static int idle_bad(Conn_t *conn);
47
48 static int data_forward(Conn_t *conn);
49 static int join_close(Conn_t *conn);
50
51 /* Data */
52 #define BUFSIZE 20000
53
54 const Unit_t conn_unit = {
55   "conn",
56   &conn_init0,
57   &conn_init1,
58   &conn_dump,
59   &conn_release
60 };
61
62 static Conn_t *connlist;
63
64 unsigned char *data_packet;
65 unsigned int data_packet_size;
66
67 static const char *rcsid = "$Id: connect_bus.c,v 1.1.1.1 2005/04/29 01:44:51 echo Exp $";
68
69 static State_t
70   /* CS_IDLE */
71   is_1 = { CE_SVC_OPEN, 0,  "Idle->Oper", join, CS_OPERATIONAL },
72   is_2 = { CE_SVC_OPEN, 0, "Idle->Idle", idle_bad, CS_IDLE },
73   *idle_state[] = { &is_1, &is_2, NULL },
74
75   /* CS_OPERATIONAL */
76   os_1 = { CE_DATA, 0, "Oper->Oper", data_forward, CS_OPERATIONAL },
77 /*  os_2 = { CE_DATA, LE_FLUSH_REQUEST, "Active->Active", flush_request,
78              CS_ACTIVE }, */
79   os_3 = { CE_SVC_CLOSE, 0, "Oper->Idle", join_close, CS_IDLE },
80   *operational_state[] = { &os_1, /*&as_2,*/ &os_3, NULL },
81
82   **transitions[CS_MAX + 1] = {
83     idle_state, NULL, operational_state
84   };
85
86 /* Functions */
87
88 /* Initialize local data */
89 static void
90 conn_init0(void)
91 {
92   connlist = NULL;
93 }
94
95 /* Initialization for data that needs other units */
96 static void
97 conn_init1(void)
98 {
99   set_var_str(&conn_unit, "version", rcsid);
100   conn_main();
101   add_event_handler(CE_DATA, &data_handler, "data_handler", NULL);
102   Debug_unit(&conn_unit, "Initialized.");
103 }
104
105 /* Dump status, local data etc. */
106 static void
107 conn_dump(void)
108 {
109   const char *tmp;
110   const AtmAddr_t *addr;
111
112   Debug_unit(&conn_unit, "Dumping unit");
113   Debug_unit(&conn_unit, "Parameters:");
114   addr = get_var_addr(&conn_unit, "S1");
115   if (addr != NULL) {
116     Debug_unit(&conn_unit, "S1:");
117     dump_atmaddr(addr);
118   }
119   else {
120     Debug_unit(&conn_unit, "S1: not set");
121   }
122   tmp = get_var_str(&conn_unit, "S2");
123   if (tmp != NULL) {
124     Debug_unit(&conn_unit, "S2: %s", tmp);
125   }
126   else {
127     Debug_unit(&conn_unit, "S2: not set", tmp);
128   }
129   Debug_unit(&conn_unit, "S3: %d", get_var_int(&conn_unit, "S3"));
130   Debug_unit(&conn_unit, "S4: %d", get_var_int(&conn_unit, "S4"));
131   Debug_unit(&conn_unit, "S5: %d", get_var_int(&conn_unit, "S5"));
132   addr = get_var_addr(&conn_unit, "S6");
133   if (addr != NULL) {
134     Debug_unit(&conn_unit, "S6:");
135     dump_atmaddr(addr);
136   }
137   else {
138     Debug_unit(&conn_unit, "S6: not set");
139   }
140   dump_conn(NULL);
141 }
142
143 /* Release allocated memory, close files etc. */
144 static void
145 conn_release(void)
146 {
147   Conn_t *tmp;
148   
149   Debug_unit(&conn_unit, "Releasing unit");
150   
151   for(tmp = connlist; tmp != NULL; tmp = tmp->next) {
152     connlist = tmp->next;
153     if (tmp->fd)
154       close(tmp->fd);
155     if (tmp->sfd)
156       close(tmp->sfd);
157     mem_free(&conn_unit, tmp);
158   }
159 }
160
161 /*
162  * Handle data arrival
163  * data points to Conn_t
164  */
165 static int
166 data_handler(const Event_t *event, void *funcdata)
167 {
168   Conn_t *tmp, *newconn;
169   int fd, nbytes;
170   static char buffer[BUFSIZE];
171   struct sockaddr_atmsvc addr;
172
173   assert(event->data != NULL);
174   tmp = (Conn_t *)event->data;
175   dump_conn(tmp);
176   if (tmp->type == CT_MAIN) {
177     nbytes = sizeof(addr);
178     memset(&addr, 0,nbytes);
179     fd = accept(tmp->fd, (struct sockaddr *)&addr, &nbytes);
180     if (fd <0) {
181       dump_error(&conn_unit, "accept");
182       if (errno == ENETRESET) { /* Switch reseted? */
183         Debug_unit(&conn_unit,"Restart. Sleeping 10 secs...");
184         sleep(10);
185         event_put(&conn_unit, CE_RESTART, NULL);
186       } else if (errno == EUNATCH) { /* Probably signalling daemon was abruptly killed */
187         Debug_unit(&conn_unit,"Exiting...");
188         event_put(&conn_unit, CE_EXIT, NULL);
189       }
190       return -1;
191     }
192     newconn = conn_add(CT_SVC_CD, fd, 0);
193     newconn->state = call_state(CE_SVC_OPEN, 0, newconn);
194   }
195   else {
196     nbytes = read(tmp->active_fd, buffer, BUFSIZE);
197     if (nbytes < 0) {
198       dump_error(&conn_unit, "read");
199       if (errno == EUNATCH)
200         event_put(&conn_unit, CE_EXIT, NULL);
201       if (errno == ENETRESET) {
202         Debug_unit(&conn_unit, "Restart. Sleeping 10 secs...");
203         sleep(10);
204         event_put(&conn_unit, CE_RESTART, NULL);
205       }
206     } else if (nbytes == 0) {
207       /* EOF */
208       Debug_unit(&conn_unit, "EOF");
209       tmp->state = call_state(CE_SVC_CLOSE, 0, tmp);
210     } else {
211       buffer[nbytes] = '\0';
212       data_packet = (unsigned char *)buffer;
213       data_packet_size=nbytes;
214       tmp->state = call_state(CE_DATA, 0, tmp);
215     }
216   }
217   mem_free(&conn_unit, event);
218   return 1;
219 }
220
221 static const char *
222 dump_conn_type(ConnType_t type)
223 {
224   switch(type) {
225   case CT_NONE: return "None";
226   case CT_MAIN: return "Main listener";
227   case CT_PVC_CD: return "PVC Control Direct";
228   case CT_PVC_DD: return "PVC Data Direct";
229   case CT_SVC_CD: return "SVC Control Direct";
230   case CT_SVC_DD: return "SVC Data Direct";
231   default: return "Bad type";
232   }
233 }
234
235 void
236 dump_conn(const Conn_t *connection)
237 {
238   Conn_t *tmp;
239   
240   for(tmp = connlist; tmp != NULL; tmp = tmp->next) {
241     if (connection == NULL || tmp == connection) {
242       Debug_unit(&conn_unit, "fd %d sfd %d state %s type %s", tmp->fd, tmp->sfd, dump_conn_state(tmp->state), dump_conn_type(tmp->type));
243     }
244   }
245 }
246
247 Conn_t *
248 conn_add(ConnType_t type, int fd, LecId_t dumb)
249 {
250   Conn_t *tmp;
251
252   tmp = (Conn_t *)mem_alloc(&conn_unit, sizeof(Conn_t));
253   tmp->fd = fd;
254   tmp->sfd = 0;
255   tmp->state = CS_IDLE;
256   tmp->type = type;
257   tmp->next = connlist;
258   connlist = tmp;
259
260   event_add_fd(fd, tmp);
261   return tmp;
262 }
263
264 void
265 conn_remove(const Conn_t *connection)
266 {
267   Conn_t *tmp, *prev;
268
269   assert(connection != NULL);
270   prev = NULL;
271   tmp = connlist;
272   while(tmp) {
273     if (tmp == connection) {
274       if (prev != NULL) {
275         prev->next = tmp->next;
276       } else {
277         connlist = tmp->next;
278       }
279       if (connection->fd) {
280         close(connection->fd);
281         event_remove_fd(connection->fd);
282       }
283       if (connection->sfd) {
284         close(connection->sfd);
285         event_remove_fd(connection->sfd);
286       }
287       mem_free(&conn_unit, tmp);
288       return;
289     }
290     prev = tmp;
291     tmp = tmp->next;
292   }
293 }
294
295 void
296 conn_set_active(void *data, int fd)
297 {
298   Conn_t *tmp = (Conn_t *)data;
299
300   assert(tmp);
301   tmp->active_fd = fd;
302 }
303
304 static void
305 conn_main(void)
306 {
307   const AtmAddr_t *addr;
308   int main_conn;
309
310   addr = get_var_addr(&conn_unit, "S6");
311   if (addr == NULL) {
312     dump_printf(EL_ERROR, "S6 (BUS Address) must be specified");
313     event_put(&conn_unit, CE_EXIT, NULL);
314   } else {
315     main_conn = atm_create_socket(MULTICAST_SEND_802_3,
316                                   get_var_addr(&conn_unit, "S6"));
317     if (main_conn >= 0) {
318       (void)conn_add(CT_MAIN, main_conn, 0);
319     }
320   }
321 }
322
323 ConnState_t
324 call_state(EventType_t event, unsigned short opcode, Conn_t *conn)
325 {
326   State_t **tmp;
327   unsigned int i = 0;
328   int ret;
329
330   Debug_unit(&conn_unit, "Call state");
331   assert(conn != NULL);
332   assert(conn->state <= CS_MAX);
333   tmp = transitions[conn->state];
334
335   for(; tmp[i] != NULL; i++) {
336     if (tmp[i]->event == event && tmp[i]->opcode == opcode) {
337       Debug_unit(&conn_unit, "Trying func %s", tmp[i]->descript);
338       ret = tmp[i]->func(conn);
339       if (ret != 0){
340         Debug_unit(&conn_unit, "Success");
341         return tmp[i]->nextstate;
342       }
343       else {
344         Debug_unit(&conn_unit, "Failed");
345       }
346     }
347     else {
348       Debug_unit(&conn_unit, "Skipping func %s", tmp[i]->descript);
349     }
350   }
351   return conn->state;
352 }
353
354 const char *
355 dump_conn_state(ConnState_t state)
356 {
357   switch(state) {
358   case CS_IDLE: return "Idle";
359   case CS_JOINING: return "Joining";
360   case CS_OPERATIONAL: return "Operational";
361   default: return "Bad state";
362   }
363 }
364
365 /*
366  * State transition functions
367  */
368 static int
369 join(Conn_t *conn)
370 {
371   int rfd;
372
373   Debug_unit(&conn_unit, "Join called");
374   dump_conn(conn);
375
376   rfd = atm_connect_back(get_var_addr(&conn_unit,"S6"),
377                          conn, MULTICAST_FORWARD_802_3);
378   if (rfd<0) { /* Calling back failed */
379     conn_remove(conn);
380     return 0;
381   } else { /* Success */
382     Debug_unit(&conn_unit, "Join successful");
383     conn->sfd = rfd;
384     event_add_fd(rfd, conn);
385     return 1;
386   }
387 }
388
389 static int
390 idle_bad(Conn_t *conn)
391 {
392   Debug_unit(&conn_unit,"Idle_bad called");
393   dump_conn(conn);
394   conn_remove(conn);
395   return 1;
396 }
397
398 static int
399 data_forward(Conn_t *conn)
400 {
401   Conn_t *tmp;
402   char packet_string[1024];
403   int rvalue;
404   int i;
405
406   Debug_unit(&conn_unit,"Data forward called");
407   dump_conn(conn);
408
409   for(tmp = connlist;tmp!=NULL;tmp=tmp->next) {
410     if (tmp->sfd >0 && tmp->type != CT_MAIN) {
411       rvalue=write(tmp->sfd, data_packet, data_packet_size);
412       if (rvalue<0) {
413         dump_error(&conn_unit, "data_forward,write");
414         dump_conn(tmp);
415       } else
416         Debug_unit(&conn_unit,"Forwarding to %d-%d bytes",tmp->sfd,
417                    data_packet_size);
418     }
419   }
420   Debug_unit(&conn_unit,"Sent packet :%ld bytes",data_packet_size);
421   for (i=0;i<data_packet_size && i < 83;i++) {
422     sprintf(&packet_string[3*i],"%2.2x ",0xff&data_packet[i]);
423   }
424   if (i==data_packet_size)
425     Debug_unit(&conn_unit,"Packet:->%s<-",packet_string);
426   else
427     Debug_unit(&conn_unit,"Packet:->%s->",packet_string);
428   Debug_unit(&conn_unit,"Returning from data forward");
429   return 1;
430 }
431
432 static int
433 join_close(Conn_t *conn)
434 {
435
436   Debug_unit(&conn_unit,"Join_close called");
437
438   dump_conn(conn);
439   conn_remove(conn);
440   return 1;
441 }
442