Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netgraph/ng_frame_relay.c
34376 views
1
/*
2
* ng_frame_relay.c
3
*/
4
5
/*-
6
* Copyright (c) 1996-1999 Whistle Communications, Inc.
7
* All rights reserved.
8
*
9
* Subject to the following obligations and disclaimer of warranty, use and
10
* redistribution of this software, in source or object code forms, with or
11
* without modifications are expressly permitted by Whistle Communications;
12
* provided, however, that:
13
* 1. Any and all reproductions of the source or object code must include the
14
* copyright notice above and the following disclaimer of warranties; and
15
* 2. No rights are granted, in any manner or form, to use Whistle
16
* Communications, Inc. trademarks, including the mark "WHISTLE
17
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18
* such appears in the above copyright notice or in the software.
19
*
20
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35
* THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36
* OF SUCH DAMAGE.
37
*
38
* Author: Julian Elischer <[email protected]>
39
* $Whistle: ng_frame_relay.c,v 1.20 1999/11/01 09:24:51 julian Exp $
40
*/
41
42
/*
43
* This node implements the frame relay protocol, not including
44
* the LMI line management. This means basically keeping track
45
* of which DLCI's are active, doing frame (de)multiplexing, etc.
46
*
47
* It has a 'downstream' hook that goes to the line, and a
48
* hook for each DLCI (eg, 'dlci16').
49
*/
50
51
#include <sys/param.h>
52
#include <sys/systm.h>
53
#include <sys/kernel.h>
54
#include <sys/errno.h>
55
#include <sys/malloc.h>
56
#include <sys/mbuf.h>
57
#include <sys/syslog.h>
58
#include <sys/ctype.h>
59
60
#include <netgraph/ng_message.h>
61
#include <netgraph/netgraph.h>
62
#include <netgraph/ng_frame_relay.h>
63
64
/*
65
* Line info, and status per channel.
66
*/
67
struct ctxinfo { /* one per active hook */
68
u_int flags;
69
#define CHAN_VALID 0x01 /* assigned to a channel */
70
#define CHAN_ACTIVE 0x02 /* bottom level active */
71
int dlci; /* the dlci assigned to this context */
72
hook_p hook; /* if there's a hook assigned.. */
73
};
74
75
#define MAX_CT 16 /* # of dlci's active at a time (POWER OF 2!) */
76
struct frmrel_softc {
77
int unit; /* which card are we? */
78
int datahooks; /* number of data hooks attached */
79
node_p node; /* netgraph node */
80
int addrlen; /* address header length */
81
int flags; /* state */
82
int mtu; /* guess */
83
u_char remote_seq; /* sequence number the remote sent */
84
u_char local_seq; /* sequence number the remote rcvd */
85
u_short ALT[1024]; /* map DLCIs to CTX */
86
#define CTX_VALID 0x8000 /* this bit means it's a valid CTX */
87
#define CTX_VALUE (MAX_CT - 1) /* mask for context part */
88
struct ctxinfo channel[MAX_CT];
89
struct ctxinfo downstream;
90
};
91
typedef struct frmrel_softc *sc_p;
92
93
#define BYTEX_EA 0x01 /* End Address. Always 0 on byte1 */
94
#define BYTE1_C_R 0x02
95
#define BYTE2_FECN 0x08 /* forwards congestion notification */
96
#define BYTE2_BECN 0x04 /* Backward congestion notification */
97
#define BYTE2_DE 0x02 /* Discard elligability */
98
#define LASTBYTE_D_C 0x02 /* last byte is dl_core or dlci info */
99
100
/* Used to do headers */
101
const static struct segment {
102
u_char mask;
103
u_char shift;
104
u_char width;
105
} makeup[] = {
106
{ 0xfc, 2, 6 },
107
{ 0xf0, 4, 4 },
108
{ 0xfe, 1, 7 },
109
{ 0xfc, 2, 6 }
110
};
111
112
#define SHIFTIN(segment, byte, dlci) \
113
{ \
114
(dlci) <<= (segment)->width; \
115
(dlci) |= \
116
(((byte) & (segment)->mask) >> (segment)->shift); \
117
}
118
119
#define SHIFTOUT(segment, byte, dlci) \
120
{ \
121
(byte) |= (((dlci) << (segment)->shift) & (segment)->mask); \
122
(dlci) >>= (segment)->width; \
123
}
124
125
/* Netgraph methods */
126
static ng_constructor_t ngfrm_constructor;
127
static ng_shutdown_t ngfrm_shutdown;
128
static ng_newhook_t ngfrm_newhook;
129
static ng_rcvdata_t ngfrm_rcvdata;
130
static ng_disconnect_t ngfrm_disconnect;
131
132
/* Other internal functions */
133
static int ngfrm_decode(node_p node, item_p item);
134
static int ngfrm_addrlen(char *hdr);
135
static int ngfrm_allocate_CTX(sc_p sc, int dlci);
136
137
/* Netgraph type */
138
static struct ng_type typestruct = {
139
.version = NG_ABI_VERSION,
140
.name = NG_FRAMERELAY_NODE_TYPE,
141
.constructor = ngfrm_constructor,
142
.shutdown = ngfrm_shutdown,
143
.newhook = ngfrm_newhook,
144
.rcvdata = ngfrm_rcvdata,
145
.disconnect = ngfrm_disconnect,
146
};
147
NETGRAPH_INIT(framerelay, &typestruct);
148
149
#define ERROUT(x) do { error = (x); goto done; } while (0)
150
151
/*
152
* Given a DLCI, return the index of the context table entry for it,
153
* Allocating a new one if needs be, or -1 if none available.
154
*/
155
static int
156
ngfrm_allocate_CTX(sc_p sc, int dlci)
157
{
158
u_int ctxnum = -1; /* what ctx number we are using */
159
volatile struct ctxinfo *CTXp = NULL;
160
161
/* Sanity check the dlci value */
162
if (dlci > 1023)
163
return (-1);
164
165
/* Check to see if we already have an entry for this DLCI */
166
if (sc->ALT[dlci]) {
167
if ((ctxnum = sc->ALT[dlci] & CTX_VALUE) < MAX_CT) {
168
CTXp = sc->channel + ctxnum;
169
} else {
170
ctxnum = -1;
171
sc->ALT[dlci] = 0; /* paranoid but... */
172
}
173
}
174
175
/*
176
* If the index has no valid entry yet, then we need to allocate a
177
* CTX number to it
178
*/
179
if (CTXp == NULL) {
180
for (ctxnum = 0; ctxnum < MAX_CT; ctxnum++) {
181
/*
182
* If the VALID flag is empty it is unused
183
*/
184
if ((sc->channel[ctxnum].flags & CHAN_VALID) == 0) {
185
bzero(sc->channel + ctxnum,
186
sizeof(struct ctxinfo));
187
CTXp = sc->channel + ctxnum;
188
sc->ALT[dlci] = ctxnum | CTX_VALID;
189
sc->channel[ctxnum].dlci = dlci;
190
sc->channel[ctxnum].flags = CHAN_VALID;
191
break;
192
}
193
}
194
}
195
196
/*
197
* If we still don't have a CTX pointer, then we never found a free
198
* spot so give up now..
199
*/
200
if (!CTXp) {
201
log(LOG_ERR, "No CTX available for dlci %d\n", dlci);
202
return (-1);
203
}
204
return (ctxnum);
205
}
206
207
/*
208
* Node constructor
209
*/
210
static int
211
ngfrm_constructor(node_p node)
212
{
213
sc_p sc;
214
215
sc = malloc(sizeof(*sc), M_NETGRAPH, M_WAITOK | M_ZERO);
216
sc->addrlen = 2; /* default */
217
218
/* Link the node and our private info */
219
NG_NODE_SET_PRIVATE(node, sc);
220
sc->node = node;
221
return (0);
222
}
223
224
/*
225
* Add a new hook
226
*
227
* We allow hooks called "debug", "downstream" and dlci[0-1023]
228
* The hook's private info points to our stash of info about that
229
* channel. A NULL pointer is debug and a DLCI of -1 means downstream.
230
*/
231
static int
232
ngfrm_newhook(node_p node, hook_p hook, const char *name)
233
{
234
const sc_p sc = NG_NODE_PRIVATE(node);
235
const char *cp;
236
char *eptr;
237
int dlci = 0;
238
int ctxnum;
239
240
/* Check if it's our friend the control hook */
241
if (strcmp(name, NG_FRAMERELAY_HOOK_DEBUG) == 0) {
242
NG_HOOK_SET_PRIVATE(hook, NULL); /* paranoid */
243
return (0);
244
}
245
246
/*
247
* All other hooks either start with 'dlci' and have a decimal
248
* trailing channel number up to 4 digits, or are the downstream
249
* hook.
250
*/
251
if (strncmp(name, NG_FRAMERELAY_HOOK_DLCI,
252
strlen(NG_FRAMERELAY_HOOK_DLCI)) != 0) {
253
/* It must be the downstream connection */
254
if (strcmp(name, NG_FRAMERELAY_HOOK_DOWNSTREAM) != 0)
255
return EINVAL;
256
257
/* Make sure we haven't already got one (paranoid) */
258
if (sc->downstream.hook)
259
return (EADDRINUSE);
260
261
/* OK add it */
262
NG_HOOK_SET_PRIVATE(hook, &sc->downstream);
263
sc->downstream.hook = hook;
264
sc->downstream.dlci = -1;
265
sc->downstream.flags |= CHAN_ACTIVE;
266
sc->datahooks++;
267
return (0);
268
}
269
270
/* Must be a dlci hook at this point */
271
cp = name + strlen(NG_FRAMERELAY_HOOK_DLCI);
272
if (!isdigit(*cp) || (cp[0] == '0' && cp[1] != '\0'))
273
return (EINVAL);
274
dlci = (int)strtoul(cp, &eptr, 10);
275
if (*eptr != '\0' || dlci < 0 || dlci > 1023)
276
return (EINVAL);
277
278
/*
279
* We have a dlci, now either find it, or allocate it. It's possible
280
* that we might have seen packets for it already and made an entry
281
* for it.
282
*/
283
ctxnum = ngfrm_allocate_CTX(sc, dlci);
284
if (ctxnum == -1)
285
return (ENOBUFS);
286
287
/*
288
* Be paranoid: if it's got a hook already, that dlci is in use .
289
* Generic code can not catch all the synonyms (e.g. dlci016 vs
290
* dlci16)
291
*/
292
if (sc->channel[ctxnum].hook != NULL)
293
return (EADDRINUSE);
294
295
/*
296
* Put our hooks into it (pun not intended)
297
*/
298
sc->channel[ctxnum].flags |= CHAN_ACTIVE;
299
NG_HOOK_SET_PRIVATE(hook, sc->channel + ctxnum);
300
sc->channel[ctxnum].hook = hook;
301
sc->datahooks++;
302
return (0);
303
}
304
305
/*
306
* Count up the size of the address header if we don't already know
307
*/
308
int
309
ngfrm_addrlen(char *hdr)
310
{
311
if (hdr[0] & BYTEX_EA)
312
return 0;
313
if (hdr[1] & BYTEX_EA)
314
return 2;
315
if (hdr[2] & BYTEX_EA)
316
return 3;
317
if (hdr[3] & BYTEX_EA)
318
return 4;
319
return 0;
320
}
321
322
/*
323
* Receive data packet
324
*/
325
static int
326
ngfrm_rcvdata(hook_p hook, item_p item)
327
{
328
struct ctxinfo *const ctxp = NG_HOOK_PRIVATE(hook);
329
struct mbuf *m = NULL;
330
int error = 0;
331
int dlci;
332
sc_p sc;
333
int alen;
334
char *data;
335
336
/* Data doesn't come in from just anywhere (e.g debug hook) */
337
if (ctxp == NULL)
338
ERROUT(ENETDOWN);
339
340
/* If coming from downstream, decode it to a channel */
341
dlci = ctxp->dlci;
342
if (dlci == -1)
343
return (ngfrm_decode(NG_HOOK_NODE(hook), item));
344
345
NGI_GET_M(item, m);
346
/* Derive the softc we will need */
347
sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
348
349
/* If there is no live channel, throw it away */
350
if ((sc->downstream.hook == NULL)
351
|| ((ctxp->flags & CHAN_ACTIVE) == 0))
352
ERROUT(ENETDOWN);
353
354
/* Store the DLCI on the front of the packet */
355
alen = sc->addrlen;
356
if (alen == 0)
357
alen = 2; /* default value for transmit */
358
M_PREPEND(m, alen, M_NOWAIT);
359
if (m == NULL)
360
ERROUT(ENOBUFS);
361
data = mtod(m, char *);
362
363
/*
364
* Shift the lowest bits into the address field until we are done.
365
* First byte is MSBits of addr so work backwards.
366
*/
367
switch (alen) {
368
case 2:
369
data[0] = data[1] = '\0';
370
SHIFTOUT(makeup + 1, data[1], dlci);
371
SHIFTOUT(makeup + 0, data[0], dlci);
372
data[1] |= BYTEX_EA;
373
break;
374
case 3:
375
data[0] = data[1] = data[2] = '\0';
376
SHIFTOUT(makeup + 3, data[2], dlci); /* 3 and 2 is correct */
377
SHIFTOUT(makeup + 1, data[1], dlci);
378
SHIFTOUT(makeup + 0, data[0], dlci);
379
data[2] |= BYTEX_EA;
380
break;
381
case 4:
382
data[0] = data[1] = data[2] = data[3] = '\0';
383
SHIFTOUT(makeup + 3, data[3], dlci);
384
SHIFTOUT(makeup + 2, data[2], dlci);
385
SHIFTOUT(makeup + 1, data[1], dlci);
386
SHIFTOUT(makeup + 0, data[0], dlci);
387
data[3] |= BYTEX_EA;
388
break;
389
default:
390
panic("%s", __func__);
391
}
392
393
/* Send it */
394
NG_FWD_NEW_DATA(error, item, sc->downstream.hook, m);
395
return (error);
396
397
done:
398
NG_FREE_ITEM(item);
399
NG_FREE_M(m);
400
return (error);
401
}
402
403
/*
404
* Decode an incoming frame coming from the switch
405
*/
406
static int
407
ngfrm_decode(node_p node, item_p item)
408
{
409
const sc_p sc = NG_NODE_PRIVATE(node);
410
char *data;
411
int alen;
412
u_int dlci = 0;
413
int error = 0;
414
int ctxnum;
415
struct mbuf *m;
416
417
NGI_GET_M(item, m);
418
if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL)
419
ERROUT(ENOBUFS);
420
data = mtod(m, char *);
421
if ((alen = sc->addrlen) == 0) {
422
sc->addrlen = alen = ngfrm_addrlen(data);
423
}
424
switch (alen) {
425
case 2:
426
SHIFTIN(makeup + 0, data[0], dlci);
427
SHIFTIN(makeup + 1, data[1], dlci);
428
break;
429
case 3:
430
SHIFTIN(makeup + 0, data[0], dlci);
431
SHIFTIN(makeup + 1, data[1], dlci);
432
SHIFTIN(makeup + 3, data[2], dlci); /* 3 and 2 is correct */
433
break;
434
case 4:
435
SHIFTIN(makeup + 0, data[0], dlci);
436
SHIFTIN(makeup + 1, data[1], dlci);
437
SHIFTIN(makeup + 2, data[2], dlci);
438
SHIFTIN(makeup + 3, data[3], dlci);
439
break;
440
default:
441
ERROUT(EINVAL);
442
}
443
444
if (dlci > 1023)
445
ERROUT(EINVAL);
446
ctxnum = sc->ALT[dlci];
447
if ((ctxnum & CTX_VALID) && sc->channel[ctxnum &= CTX_VALUE].hook) {
448
/* Send it */
449
m_adj(m, alen);
450
NG_FWD_NEW_DATA(error, item, sc->channel[ctxnum].hook, m);
451
return (error);
452
} else {
453
error = ENETDOWN;
454
}
455
done:
456
NG_FREE_ITEM(item);
457
NG_FREE_M(m);
458
return (error);
459
}
460
461
/*
462
* Shutdown node
463
*/
464
static int
465
ngfrm_shutdown(node_p node)
466
{
467
const sc_p sc = NG_NODE_PRIVATE(node);
468
469
NG_NODE_SET_PRIVATE(node, NULL);
470
free(sc, M_NETGRAPH);
471
NG_NODE_UNREF(node);
472
return (0);
473
}
474
475
/*
476
* Hook disconnection
477
*
478
* Invalidate the private data associated with this dlci.
479
* For this type, removal of the last link resets tries to destroy the node.
480
*/
481
static int
482
ngfrm_disconnect(hook_p hook)
483
{
484
const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
485
struct ctxinfo *const cp = NG_HOOK_PRIVATE(hook);
486
int dlci;
487
488
/* If it's a regular dlci hook, then free resources etc.. */
489
if (cp != NULL) {
490
cp->hook = NULL;
491
dlci = cp->dlci;
492
if (dlci != -1)
493
sc->ALT[dlci] = 0;
494
cp->flags = 0;
495
sc->datahooks--;
496
}
497
if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
498
&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
499
ng_rmnode_self(NG_HOOK_NODE(hook));
500
return (0);
501
}
502
503