1 |
dpavlin |
1 |
/* |
2 |
dpavlin |
7 |
* Cisco router simulation platform. |
3 |
dpavlin |
1 |
* Copyright (c) 2006 Christophe Fillot (cf@utc.fr) |
4 |
|
|
* |
5 |
|
|
* Frame-Relay switch. |
6 |
|
|
*/ |
7 |
|
|
|
8 |
|
|
#include <stdio.h> |
9 |
|
|
#include <stdlib.h> |
10 |
|
|
#include <string.h> |
11 |
|
|
#include <unistd.h> |
12 |
|
|
#include <pthread.h> |
13 |
|
|
#include <errno.h> |
14 |
|
|
#include <sys/select.h> |
15 |
|
|
#include <sys/time.h> |
16 |
|
|
#include <sys/types.h> |
17 |
|
|
|
18 |
|
|
#include "utils.h" |
19 |
|
|
#include "mempool.h" |
20 |
|
|
#include "registry.h" |
21 |
|
|
#include "net_io.h" |
22 |
|
|
#include "frame_relay.h" |
23 |
|
|
|
24 |
|
|
#define DEBUG_FRSW 0 |
25 |
|
|
|
26 |
|
|
extern FILE *log_file; |
27 |
|
|
|
28 |
|
|
/* ANSI LMI packet header */ |
29 |
|
|
static const m_uint8_t lmi_ansi_hdr[] = { |
30 |
|
|
0x00, 0x01, 0x03, 0x08, 0x00, 0x75, 0x95, |
31 |
|
|
}; |
32 |
|
|
|
33 |
|
|
/* DLCI hash function */ |
34 |
|
|
static inline u_int frsw_dlci_hash(u_int dlci) |
35 |
|
|
{ |
36 |
|
|
return((dlci ^ (dlci >> 8)) & (FRSW_HASH_SIZE-1)); |
37 |
|
|
} |
38 |
|
|
|
39 |
|
|
/* DLCI lookup */ |
40 |
|
|
frsw_conn_t *frsw_dlci_lookup(frsw_table_t *t,netio_desc_t *input,u_int dlci) |
41 |
|
|
{ |
42 |
|
|
frsw_conn_t *vc; |
43 |
|
|
|
44 |
|
|
for(vc=t->dlci_table[frsw_dlci_hash(dlci)];vc;vc=vc->hash_next) |
45 |
|
|
if ((vc->input == input) && (vc->dlci_in == dlci)) |
46 |
|
|
return vc; |
47 |
|
|
|
48 |
|
|
return NULL; |
49 |
|
|
} |
50 |
|
|
|
51 |
|
|
/* Handle a ANSI LMI packet */ |
52 |
|
|
ssize_t frsw_handle_lmi_ansi_pkt(frsw_table_t *t,netio_desc_t *input, |
53 |
|
|
m_uint8_t *pkt,ssize_t len) |
54 |
|
|
{ |
55 |
|
|
m_uint8_t resp[FR_MAX_PKT_SIZE],*pres,*preq; |
56 |
|
|
m_uint8_t itype,isize; |
57 |
|
|
int msg_type,seq_ok; |
58 |
|
|
ssize_t rlen; |
59 |
|
|
frsw_conn_t *sc; |
60 |
|
|
u_int dlci; |
61 |
|
|
|
62 |
dpavlin |
11 |
if ((len <= sizeof(lmi_ansi_hdr)) || |
63 |
dpavlin |
1 |
memcmp(pkt,lmi_ansi_hdr,sizeof(lmi_ansi_hdr))) |
64 |
|
|
return(-1); |
65 |
|
|
|
66 |
|
|
#if DEBUG_FRSW |
67 |
|
|
m_log(input->name,"received an ANSI LMI packet:\n"); |
68 |
|
|
mem_dump(log_file,pkt,len); |
69 |
|
|
#endif |
70 |
|
|
|
71 |
|
|
/* Prepare response packet */ |
72 |
|
|
memcpy(resp,lmi_ansi_hdr,sizeof(lmi_ansi_hdr)); |
73 |
|
|
resp[FR_LMI_ANSI_STATUS_OFFSET] = FR_LMI_ANSI_STATUS; |
74 |
|
|
|
75 |
|
|
preq = &pkt[sizeof(lmi_ansi_hdr)]; |
76 |
|
|
pres = &resp[sizeof(lmi_ansi_hdr)]; |
77 |
|
|
|
78 |
|
|
msg_type = -1; |
79 |
|
|
seq_ok = FALSE; |
80 |
|
|
|
81 |
|
|
while((preq + 2) < (pkt + len)) { |
82 |
|
|
/* get item type and size */ |
83 |
|
|
itype = preq[0]; |
84 |
|
|
isize = preq[1]; |
85 |
|
|
|
86 |
|
|
/* check packet boundary */ |
87 |
|
|
if ((preq + isize + 2) > (pkt + len)) { |
88 |
|
|
m_log(input->name,"invalid LMI packet:\n"); |
89 |
|
|
mem_dump(log_file,pkt,len); |
90 |
|
|
return(-1); |
91 |
|
|
} |
92 |
|
|
|
93 |
|
|
switch(itype) { |
94 |
|
|
case 0x01: /* report information element */ |
95 |
|
|
if (isize != 1) { |
96 |
|
|
m_log(input->name,"invalid LMI item size.\n"); |
97 |
|
|
return(-1); |
98 |
|
|
} |
99 |
|
|
|
100 |
|
|
if ((msg_type = preq[2]) > 1) { |
101 |
|
|
m_log(input->name,"unknown LMI report type 0x%x.\n",msg_type); |
102 |
|
|
return(-1); |
103 |
|
|
} |
104 |
|
|
|
105 |
|
|
pres[0] = 0x01; |
106 |
|
|
pres[1] = 0x01; |
107 |
|
|
pres[2] = msg_type; |
108 |
|
|
pres += 3; |
109 |
|
|
break; |
110 |
|
|
|
111 |
|
|
case 0x03: /* sequences */ |
112 |
|
|
if (isize != 2) { |
113 |
|
|
m_log(input->name,"invalid LMI item size.\n"); |
114 |
|
|
return(-1); |
115 |
|
|
} |
116 |
|
|
|
117 |
|
|
pres[0] = 0x03; |
118 |
|
|
pres[1] = 0x02; |
119 |
|
|
|
120 |
|
|
if (input->fr_lmi_seq != preq[3]) { |
121 |
|
|
m_log(input->name,"resynchronization with LMI sequence...\n"); |
122 |
|
|
input->fr_lmi_seq = preq[3]; |
123 |
|
|
} |
124 |
|
|
|
125 |
|
|
input->fr_lmi_seq++; |
126 |
|
|
if (!input->fr_lmi_seq) input->fr_lmi_seq++; |
127 |
|
|
pres[2] = input->fr_lmi_seq; |
128 |
|
|
pres[3] = preq[2]; |
129 |
|
|
|
130 |
|
|
#if DEBUG_FRSW |
131 |
|
|
m_log(input->name,"iSSN=0x%x, iRSN=0x%x, oSSN=0x%x, oRSN=0x%x\n", |
132 |
|
|
preq[2],preq[3],pres[2],pres[3]); |
133 |
|
|
#endif |
134 |
|
|
pres += 4; |
135 |
|
|
seq_ok = TRUE; |
136 |
|
|
break; |
137 |
|
|
|
138 |
|
|
default: |
139 |
|
|
m_log(input->name,"unknown LMI item type %u\n",itype); |
140 |
|
|
goto done; |
141 |
|
|
} |
142 |
|
|
|
143 |
|
|
/* proceed next item */ |
144 |
|
|
preq += isize + 2; |
145 |
|
|
} |
146 |
|
|
|
147 |
|
|
done: |
148 |
|
|
if ((msg_type == -1) || !seq_ok) { |
149 |
|
|
m_log(input->name,"incomplete LMI packet.\n"); |
150 |
|
|
return(-1); |
151 |
|
|
} |
152 |
|
|
|
153 |
|
|
/* full status, send DLCI info */ |
154 |
|
|
if (msg_type == 0) { |
155 |
|
|
#if DEBUG_FRSW |
156 |
|
|
m_log(input->name,"LMI full status, advertising DLCIs\n"); |
157 |
|
|
#endif |
158 |
|
|
for(sc=input->fr_conn_list;sc;sc=sc->next) { |
159 |
|
|
dlci = sc->dlci_in; |
160 |
|
|
#if DEBUG_FRSW |
161 |
|
|
m_log(input->name,"sending LMI adv for DLCI %u\n",dlci); |
162 |
|
|
#endif |
163 |
|
|
pres[0] = 0x07; |
164 |
|
|
pres[1] = 0x03; |
165 |
|
|
pres[2] = dlci >> 4; |
166 |
|
|
pres[3] = 0x80 | ((dlci & 0x0f) << 3); |
167 |
|
|
pres[4] = 0x82; |
168 |
|
|
pres += 5; |
169 |
|
|
} |
170 |
|
|
} |
171 |
|
|
|
172 |
|
|
rlen = pres - resp; |
173 |
|
|
|
174 |
|
|
#if DEBUG_FRSW |
175 |
|
|
m_log(input->name,"sending ANSI LMI packet:\n"); |
176 |
|
|
mem_dump(log_file,resp,rlen); |
177 |
|
|
#endif |
178 |
|
|
|
179 |
|
|
netio_send(input,resp,rlen); |
180 |
|
|
return(0); |
181 |
|
|
} |
182 |
|
|
|
183 |
|
|
/* DLCI switching */ |
184 |
|
|
void frsw_dlci_switch(frsw_conn_t *vc,m_uint8_t *pkt) |
185 |
|
|
{ |
186 |
|
|
pkt[0] = (pkt[0] & 0x03) | ((vc->dlci_out >> 4) << 2); |
187 |
|
|
pkt[1] = (pkt[1] & 0x0f) | ((vc->dlci_out & 0x0f) << 4); |
188 |
|
|
|
189 |
|
|
/* update the statistics counter */ |
190 |
|
|
vc->count++; |
191 |
|
|
} |
192 |
|
|
|
193 |
|
|
/* Handle a Frame-Relay packet */ |
194 |
|
|
ssize_t frsw_handle_pkt(frsw_table_t *t,netio_desc_t *input, |
195 |
|
|
m_uint8_t *pkt,ssize_t len) |
196 |
|
|
{ |
197 |
|
|
netio_desc_t *output = NULL; |
198 |
|
|
frsw_conn_t *vc; |
199 |
|
|
m_uint32_t dlci; |
200 |
|
|
ssize_t slen; |
201 |
|
|
|
202 |
|
|
/* Extract DLCI information */ |
203 |
|
|
dlci = ((pkt[0] & 0xfc) >> 2) << 4; |
204 |
|
|
dlci |= (pkt[1] & 0xf0) >> 4; |
205 |
|
|
|
206 |
|
|
#if DEBUG_FRSW |
207 |
|
|
m_log(input->name,"Trying to switch packet with input DLCI %u.\n",dlci); |
208 |
|
|
mem_dump(log_file,pkt,len); |
209 |
|
|
#endif |
210 |
|
|
|
211 |
|
|
/* LMI ? */ |
212 |
|
|
if (dlci == FR_DLCI_LMI_ANSI) |
213 |
|
|
return(frsw_handle_lmi_ansi_pkt(t,input,pkt,len)); |
214 |
|
|
|
215 |
|
|
/* DLCI switching */ |
216 |
|
|
if ((vc = frsw_dlci_lookup(t,input,dlci)) != NULL) { |
217 |
|
|
frsw_dlci_switch(vc,pkt); |
218 |
|
|
output = vc->output; |
219 |
|
|
} |
220 |
|
|
|
221 |
|
|
#if DEBUG_FRSW |
222 |
|
|
if (output) { |
223 |
|
|
m_log(input->name,"Switching packet to interface %s.\n",output->name); |
224 |
|
|
} else { |
225 |
|
|
m_log(input->name,"Unable to switch packet.\n"); |
226 |
|
|
} |
227 |
|
|
#endif |
228 |
|
|
|
229 |
|
|
/* Send the packet on output interface */ |
230 |
|
|
slen = netio_send(output,pkt,len); |
231 |
|
|
|
232 |
|
|
if (len != slen) { |
233 |
|
|
t->drop++; |
234 |
|
|
return(-1); |
235 |
|
|
} |
236 |
|
|
|
237 |
|
|
return(0); |
238 |
|
|
} |
239 |
|
|
|
240 |
|
|
/* Receive a Frame-Relay packet */ |
241 |
|
|
static int frsw_recv_pkt(netio_desc_t *nio,u_char *pkt,ssize_t pkt_len, |
242 |
|
|
frsw_table_t *t) |
243 |
|
|
{ |
244 |
|
|
int res; |
245 |
|
|
|
246 |
|
|
FRSW_LOCK(t); |
247 |
|
|
res = frsw_handle_pkt(t,nio,pkt,pkt_len); |
248 |
|
|
FRSW_UNLOCK(t); |
249 |
|
|
return(res); |
250 |
|
|
} |
251 |
|
|
|
252 |
|
|
/* Acquire a reference to a Frame-Relay switch (increment reference count) */ |
253 |
|
|
frsw_table_t *frsw_acquire(char *name) |
254 |
|
|
{ |
255 |
|
|
return(registry_find(name,OBJ_TYPE_FRSW)); |
256 |
|
|
} |
257 |
|
|
|
258 |
|
|
/* Release a Frame-Relay switch (decrement reference count) */ |
259 |
|
|
int frsw_release(char *name) |
260 |
|
|
{ |
261 |
|
|
return(registry_unref(name,OBJ_TYPE_FRSW)); |
262 |
|
|
} |
263 |
|
|
|
264 |
|
|
/* Create a virtual switch table */ |
265 |
|
|
frsw_table_t *frsw_create_table(char *name) |
266 |
|
|
{ |
267 |
|
|
frsw_table_t *t; |
268 |
|
|
|
269 |
|
|
/* Allocate a new switch structure */ |
270 |
|
|
if (!(t = malloc(sizeof(*t)))) |
271 |
|
|
return NULL; |
272 |
|
|
|
273 |
|
|
memset(t,0,sizeof(*t)); |
274 |
|
|
pthread_mutex_init(&t->lock,NULL); |
275 |
|
|
mp_create_fixed_pool(&t->mp,"Frame-Relay Switch"); |
276 |
|
|
|
277 |
|
|
if (!(t->name = mp_strdup(&t->mp,name))) |
278 |
|
|
goto err_name; |
279 |
|
|
|
280 |
|
|
/* Record this object in registry */ |
281 |
|
|
if (registry_add(t->name,OBJ_TYPE_FRSW,t) == -1) { |
282 |
|
|
fprintf(stderr,"frsw_create_table: unable to create switch '%s'\n",name); |
283 |
|
|
goto err_reg; |
284 |
|
|
} |
285 |
|
|
|
286 |
|
|
return t; |
287 |
|
|
|
288 |
|
|
err_reg: |
289 |
|
|
err_name: |
290 |
|
|
mp_free_pool(&t->mp); |
291 |
|
|
free(t); |
292 |
|
|
return NULL; |
293 |
|
|
} |
294 |
|
|
|
295 |
|
|
/* Unlink a VC */ |
296 |
|
|
static void frsw_unlink_vc(frsw_conn_t *vc) |
297 |
|
|
{ |
298 |
|
|
if (vc) { |
299 |
|
|
if (vc->next) |
300 |
|
|
vc->next->pprev = vc->pprev; |
301 |
|
|
|
302 |
|
|
if (vc->pprev) |
303 |
|
|
*(vc->pprev) = vc->next; |
304 |
|
|
} |
305 |
|
|
} |
306 |
|
|
|
307 |
|
|
/* Free resources used by a VC */ |
308 |
|
|
static void frsw_release_vc(frsw_conn_t *vc) |
309 |
|
|
{ |
310 |
|
|
if (vc) { |
311 |
|
|
/* release input NIO */ |
312 |
|
|
if (vc->input) { |
313 |
|
|
netio_rxl_remove(vc->input); |
314 |
|
|
netio_release(vc->input->name); |
315 |
|
|
} |
316 |
|
|
|
317 |
|
|
/* release output NIO */ |
318 |
|
|
if (vc->output) |
319 |
|
|
netio_release(vc->output->name); |
320 |
|
|
} |
321 |
|
|
} |
322 |
|
|
|
323 |
|
|
/* Free resources used by a Frame-Relay switch */ |
324 |
|
|
static int frsw_free(void *data,void *arg) |
325 |
|
|
{ |
326 |
|
|
frsw_table_t *t = data; |
327 |
|
|
frsw_conn_t *vc; |
328 |
|
|
int i; |
329 |
|
|
|
330 |
|
|
for(i=0;i<FRSW_HASH_SIZE;i++) |
331 |
|
|
for(vc=t->dlci_table[i];vc;vc=vc->hash_next) |
332 |
|
|
frsw_release_vc(vc); |
333 |
|
|
|
334 |
|
|
mp_free_pool(&t->mp); |
335 |
|
|
free(t); |
336 |
|
|
return(TRUE); |
337 |
|
|
} |
338 |
|
|
|
339 |
|
|
/* Delete a Frame-Relay switch */ |
340 |
|
|
int frsw_delete(char *name) |
341 |
|
|
{ |
342 |
|
|
return(registry_delete_if_unused(name,OBJ_TYPE_FRSW,frsw_free,NULL)); |
343 |
|
|
} |
344 |
|
|
|
345 |
|
|
/* Delete all Frame-Relay switches */ |
346 |
|
|
int frsw_delete_all(void) |
347 |
|
|
{ |
348 |
|
|
return(registry_delete_type(OBJ_TYPE_FRSW,frsw_free,NULL)); |
349 |
|
|
} |
350 |
|
|
|
351 |
|
|
/* Create a switch connection */ |
352 |
|
|
int frsw_create_vc(frsw_table_t *t,char *nio_input,u_int dlci_in, |
353 |
|
|
char *nio_output,u_int dlci_out) |
354 |
|
|
{ |
355 |
|
|
frsw_conn_t *vc,**p; |
356 |
|
|
u_int hbucket; |
357 |
|
|
|
358 |
|
|
FRSW_LOCK(t); |
359 |
|
|
|
360 |
|
|
/* Allocate a new VC */ |
361 |
|
|
if (!(vc = mp_alloc(&t->mp,sizeof(*vc)))) { |
362 |
|
|
FRSW_UNLOCK(t); |
363 |
|
|
return(-1); |
364 |
|
|
} |
365 |
|
|
|
366 |
|
|
vc->input = netio_acquire(nio_input); |
367 |
|
|
vc->output = netio_acquire(nio_output); |
368 |
|
|
vc->dlci_in = dlci_in; |
369 |
|
|
vc->dlci_out = dlci_out; |
370 |
|
|
|
371 |
|
|
/* Check these NIOs are valid and the input VC does not exists */ |
372 |
|
|
if (!vc->input || !vc->output) |
373 |
|
|
goto error; |
374 |
|
|
|
375 |
|
|
if (frsw_dlci_lookup(t,vc->input,dlci_in)) { |
376 |
|
|
fprintf(stderr,"FRSW %s: switching for VC %u on IF %s " |
377 |
|
|
"already defined.\n",t->name,dlci_in,vc->input->name); |
378 |
|
|
goto error; |
379 |
|
|
} |
380 |
|
|
|
381 |
|
|
/* Add as a RX listener */ |
382 |
|
|
if (netio_rxl_add(vc->input,(netio_rx_handler_t)frsw_recv_pkt,t,NULL) == -1) |
383 |
|
|
goto error; |
384 |
|
|
|
385 |
|
|
hbucket = frsw_dlci_hash(dlci_in); |
386 |
|
|
vc->hash_next = t->dlci_table[hbucket]; |
387 |
|
|
t->dlci_table[hbucket] = vc; |
388 |
|
|
|
389 |
|
|
for(p=(frsw_conn_t **)&vc->input->fr_conn_list;*p;p=&(*p)->next) |
390 |
|
|
if ((*p)->dlci_in > dlci_in) |
391 |
|
|
break; |
392 |
|
|
|
393 |
|
|
vc->next = *p; |
394 |
|
|
if (*p) (*p)->pprev = &vc->next; |
395 |
|
|
vc->pprev = p; |
396 |
|
|
*p = vc; |
397 |
|
|
|
398 |
|
|
FRSW_UNLOCK(t); |
399 |
|
|
return(0); |
400 |
|
|
|
401 |
|
|
error: |
402 |
|
|
FRSW_UNLOCK(t); |
403 |
|
|
frsw_release_vc(vc); |
404 |
|
|
mp_free(vc); |
405 |
|
|
return(-1); |
406 |
|
|
} |
407 |
|
|
|
408 |
|
|
/* Remove a switch connection */ |
409 |
|
|
int frsw_delete_vc(frsw_table_t *t,char *nio_input,u_int dlci_in, |
410 |
|
|
char *nio_output,u_int dlci_out) |
411 |
|
|
{ |
412 |
|
|
netio_desc_t *input,*output; |
413 |
|
|
frsw_conn_t **vc,*p; |
414 |
|
|
u_int hbucket; |
415 |
|
|
|
416 |
|
|
FRSW_LOCK(t); |
417 |
|
|
|
418 |
|
|
input = registry_exists(nio_input,OBJ_TYPE_NIO); |
419 |
|
|
output = registry_exists(nio_output,OBJ_TYPE_NIO); |
420 |
|
|
|
421 |
|
|
if (!input || !output) { |
422 |
|
|
FRSW_UNLOCK(t); |
423 |
|
|
return(-1); |
424 |
|
|
} |
425 |
|
|
|
426 |
|
|
hbucket = frsw_dlci_hash(dlci_in); |
427 |
|
|
for(vc=&t->dlci_table[hbucket];*vc;vc=&(*vc)->hash_next) |
428 |
|
|
{ |
429 |
|
|
p = *vc; |
430 |
|
|
|
431 |
|
|
if ((p->input == input) && (p->output == output) && |
432 |
|
|
(p->dlci_in == dlci_in) && (p->dlci_out == dlci_out)) |
433 |
|
|
{ |
434 |
|
|
/* Found a matching VC, remove it */ |
435 |
|
|
*vc = (*vc)->hash_next; |
436 |
|
|
frsw_unlink_vc(p); |
437 |
|
|
FRSW_UNLOCK(t); |
438 |
|
|
|
439 |
|
|
/* Release NIOs */ |
440 |
|
|
frsw_release_vc(p); |
441 |
dpavlin |
11 |
mp_free(p); |
442 |
dpavlin |
1 |
return(0); |
443 |
|
|
} |
444 |
|
|
} |
445 |
|
|
|
446 |
|
|
FRSW_UNLOCK(t); |
447 |
|
|
return(-1); |
448 |
|
|
} |
449 |
|
|
|
450 |
|
|
/* Save the configuration of a Frame-Relay switch */ |
451 |
|
|
void frsw_save_config(frsw_table_t *t,FILE *fd) |
452 |
|
|
{ |
453 |
|
|
frsw_conn_t *vc; |
454 |
|
|
int i; |
455 |
|
|
|
456 |
|
|
fprintf(fd,"frsw create %s\n",t->name); |
457 |
|
|
|
458 |
|
|
FRSW_LOCK(t); |
459 |
|
|
|
460 |
|
|
for(i=0;i<FRSW_HASH_SIZE;i++) { |
461 |
|
|
for(vc=t->dlci_table[i];vc;vc=vc->next) { |
462 |
|
|
fprintf(fd,"frsw create_vc %s %s %u %s %u\n", |
463 |
|
|
t->name,vc->input->name,vc->dlci_in, |
464 |
|
|
vc->output->name,vc->dlci_out); |
465 |
|
|
} |
466 |
|
|
} |
467 |
|
|
|
468 |
|
|
FRSW_UNLOCK(t); |
469 |
|
|
|
470 |
|
|
fprintf(fd,"\n"); |
471 |
|
|
} |
472 |
|
|
|
473 |
|
|
/* Save configurations of all Frame-Relay switches */ |
474 |
|
|
static void frsw_reg_save_config(registry_entry_t *entry,void *opt,int *err) |
475 |
|
|
{ |
476 |
|
|
frsw_save_config((frsw_table_t *)entry->data,(FILE *)opt); |
477 |
|
|
} |
478 |
|
|
|
479 |
|
|
void frsw_save_config_all(FILE *fd) |
480 |
|
|
{ |
481 |
|
|
registry_foreach_type(OBJ_TYPE_FRSW,frsw_reg_save_config,fd,NULL); |
482 |
|
|
} |
483 |
|
|
|
484 |
|
|
/* Create a new interface */ |
485 |
|
|
int frsw_cfg_create_if(frsw_table_t *t,char **tokens,int count) |
486 |
|
|
{ |
487 |
|
|
netio_desc_t *nio = NULL; |
488 |
|
|
int nio_type; |
489 |
|
|
|
490 |
|
|
/* at least: IF, interface name, NetIO type */ |
491 |
|
|
if (count < 3) { |
492 |
|
|
fprintf(stderr,"frsw_cfg_create_if: invalid interface description\n"); |
493 |
|
|
return(-1); |
494 |
|
|
} |
495 |
|
|
|
496 |
|
|
nio_type = netio_get_type(tokens[2]); |
497 |
|
|
switch(nio_type) { |
498 |
|
|
case NETIO_TYPE_UNIX: |
499 |
|
|
if (count != 5) { |
500 |
|
|
fprintf(stderr,"FRSW: invalid number of arguments " |
501 |
|
|
"for UNIX NIO '%s'\n",tokens[1]); |
502 |
|
|
break; |
503 |
|
|
} |
504 |
|
|
|
505 |
|
|
nio = netio_desc_create_unix(tokens[1],tokens[3],tokens[4]); |
506 |
|
|
break; |
507 |
|
|
|
508 |
|
|
case NETIO_TYPE_UDP: |
509 |
|
|
if (count != 6) { |
510 |
|
|
fprintf(stderr,"FRSW: invalid number of arguments " |
511 |
|
|
"for UDP NIO '%s'\n",tokens[1]); |
512 |
|
|
break; |
513 |
|
|
} |
514 |
|
|
|
515 |
|
|
nio = netio_desc_create_udp(tokens[1],atoi(tokens[3]), |
516 |
|
|
tokens[4],atoi(tokens[5])); |
517 |
|
|
break; |
518 |
|
|
|
519 |
|
|
case NETIO_TYPE_TCP_CLI: |
520 |
|
|
if (count != 5) { |
521 |
|
|
fprintf(stderr,"FRSW: invalid number of arguments " |
522 |
|
|
"for TCP CLI NIO '%s'\n",tokens[1]); |
523 |
|
|
break; |
524 |
|
|
} |
525 |
|
|
|
526 |
|
|
nio = netio_desc_create_tcp_cli(tokens[1],tokens[3],tokens[4]); |
527 |
|
|
break; |
528 |
|
|
|
529 |
|
|
case NETIO_TYPE_TCP_SER: |
530 |
|
|
if (count != 4) { |
531 |
|
|
fprintf(stderr,"FRSW: invalid number of arguments " |
532 |
|
|
"for TCP SER NIO '%s'\n",tokens[1]); |
533 |
|
|
break; |
534 |
|
|
} |
535 |
|
|
|
536 |
|
|
nio = netio_desc_create_tcp_ser(tokens[1],tokens[3]); |
537 |
|
|
break; |
538 |
|
|
|
539 |
|
|
default: |
540 |
|
|
fprintf(stderr,"FRSW: unknown/invalid NETIO type '%s'\n", |
541 |
|
|
tokens[2]); |
542 |
|
|
} |
543 |
|
|
|
544 |
|
|
if (!nio) { |
545 |
|
|
fprintf(stderr,"FRSW: unable to create NETIO descriptor of " |
546 |
|
|
"interface %s\n",tokens[1]); |
547 |
|
|
return(-1); |
548 |
|
|
} |
549 |
|
|
|
550 |
|
|
netio_release(nio->name); |
551 |
|
|
return(0); |
552 |
|
|
} |
553 |
|
|
|
554 |
|
|
/* Create a new virtual circuit */ |
555 |
|
|
int frsw_cfg_create_vc(frsw_table_t *t,char **tokens,int count) |
556 |
|
|
{ |
557 |
|
|
/* 5 parameters: "VC", InputIF, InDLCI, OutputIF, OutDLCI */ |
558 |
|
|
if (count != 5) { |
559 |
|
|
fprintf(stderr,"FRSW: invalid VPC descriptor.\n"); |
560 |
|
|
return(-1); |
561 |
|
|
} |
562 |
|
|
|
563 |
|
|
return(frsw_create_vc(t,tokens[1],atoi(tokens[2]), |
564 |
|
|
tokens[3],atoi(tokens[4]))); |
565 |
|
|
} |
566 |
|
|
|
567 |
|
|
#define FRSW_MAX_TOKENS 16 |
568 |
|
|
|
569 |
|
|
/* Handle a FRSW configuration line */ |
570 |
|
|
int frsw_handle_cfg_line(frsw_table_t *t,char *str) |
571 |
|
|
{ |
572 |
|
|
char *tokens[FRSW_MAX_TOKENS]; |
573 |
|
|
int count; |
574 |
|
|
|
575 |
|
|
if ((count = m_strsplit(str,':',tokens,FRSW_MAX_TOKENS)) <= 1) |
576 |
|
|
return(-1); |
577 |
|
|
|
578 |
|
|
if (!strcmp(tokens[0],"IF")) |
579 |
|
|
return(frsw_cfg_create_if(t,tokens,count)); |
580 |
|
|
else if (!strcmp(tokens[0],"VC")) |
581 |
|
|
return(frsw_cfg_create_vc(t,tokens,count)); |
582 |
|
|
|
583 |
|
|
fprintf(stderr,"FRSW: Unknown statement \"%s\" (allowed: IF,VC)\n", |
584 |
|
|
tokens[0]); |
585 |
|
|
return(-1); |
586 |
|
|
} |
587 |
|
|
|
588 |
|
|
/* Read a FRSW configuration file */ |
589 |
|
|
int frsw_read_cfg_file(frsw_table_t *t,char *filename) |
590 |
|
|
{ |
591 |
|
|
char buffer[1024],*ptr; |
592 |
|
|
FILE *fd; |
593 |
|
|
|
594 |
|
|
if (!(fd = fopen(filename,"r"))) { |
595 |
|
|
perror("fopen"); |
596 |
|
|
return(-1); |
597 |
|
|
} |
598 |
|
|
|
599 |
|
|
while(!feof(fd)) { |
600 |
|
|
if (!fgets(buffer,sizeof(buffer),fd)) |
601 |
|
|
break; |
602 |
|
|
|
603 |
|
|
/* skip comments and end of line */ |
604 |
|
|
if ((ptr = strpbrk(buffer,"#\r\n")) != NULL) |
605 |
|
|
*ptr = 0; |
606 |
|
|
|
607 |
|
|
/* analyze non-empty lines */ |
608 |
|
|
if (strchr(buffer,':')) |
609 |
|
|
frsw_handle_cfg_line(t,buffer); |
610 |
|
|
} |
611 |
|
|
|
612 |
|
|
fclose(fd); |
613 |
|
|
return(0); |
614 |
|
|
} |
615 |
|
|
|
616 |
|
|
/* Start a virtual Frame-Relay switch */ |
617 |
|
|
int frsw_start(char *filename) |
618 |
|
|
{ |
619 |
|
|
frsw_table_t *t; |
620 |
|
|
|
621 |
|
|
if (!(t = frsw_create_table("default"))) { |
622 |
|
|
fprintf(stderr,"FRSW: unable to create virtual fabric table.\n"); |
623 |
|
|
return(-1); |
624 |
|
|
} |
625 |
|
|
|
626 |
|
|
if (frsw_read_cfg_file(t,filename) == -1) { |
627 |
|
|
fprintf(stderr,"FRSW: unable to parse configuration file.\n"); |
628 |
|
|
return(-1); |
629 |
|
|
} |
630 |
|
|
|
631 |
|
|
frsw_release("default"); |
632 |
|
|
return(0); |
633 |
|
|
} |