FreeBSD/Linux Kernel Cross Reference
sys/netatm/atm_subr.c
1 /*-
2 * ===================================
3 * HARP | Host ATM Research Platform
4 * ===================================
5 *
6 *
7 * This Host ATM Research Platform ("HARP") file (the "Software") is
8 * made available by Network Computing Services, Inc. ("NetworkCS")
9 * "AS IS". NetworkCS does not provide maintenance, improvements or
10 * support of any kind.
11 *
12 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
13 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
14 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
15 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
16 * In no event shall NetworkCS be responsible for any damages, including
17 * but not limited to consequential damages, arising from or relating to
18 * any use of the Software or related support.
19 *
20 * Copyright 1994-1998 Network Computing Services, Inc.
21 *
22 * Copies of this Software may be made, however, the above copyright
23 * notice must be reproduced on all copies.
24 */
25
26 /*
27 * Core ATM Services
28 * -----------------
29 *
30 * Miscellaneous ATM subroutines
31 */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/errno.h>
39 #include <sys/malloc.h>
40 #include <sys/time.h>
41 #include <sys/kernel.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/sysctl.h>
45 #include <net/if.h>
46 #include <net/netisr.h>
47 #include <netatm/port.h>
48 #include <netatm/queue.h>
49 #include <netatm/atm.h>
50 #include <netatm/atm_sys.h>
51 #include <netatm/atm_sap.h>
52 #include <netatm/atm_cm.h>
53 #include <netatm/atm_if.h>
54 #include <netatm/atm_stack.h>
55 #include <netatm/atm_pcb.h>
56 #include <netatm/atm_var.h>
57 #include <vm/uma.h>
58
59 /*
60 * Global variables
61 */
62 struct atm_pif *atm_interface_head = NULL;
63 struct atm_ncm *atm_netconv_head = NULL;
64 Atm_endpoint *atm_endpoints[ENDPT_MAX+1] = {NULL};
65 struct stackq_entry *atm_stackq_head = NULL, *atm_stackq_tail;
66 struct atm_sock_stat atm_sock_stat = { { 0 } };
67 int atm_init = 0;
68 int atm_version = ATM_VERSION;
69 struct timeval atm_debugtime = {0, 0};
70 struct ifqueue atm_intrq;
71
72 uma_zone_t atm_attributes_zone;
73
74 /*
75 * net.harp.atm.atm_debug
76 */
77 int atm_debug;
78 SYSCTL_INT(_net_harp_atm, OID_AUTO, atm_debug, CTLFLAG_RW,
79 &atm_debug, 0, "HARP ATM layer debugging flag");
80
81 /*
82 * net.harp.atm.atm_dev_print
83 */
84 int atm_dev_print;
85 SYSCTL_INT(_net_harp_atm, OID_AUTO, atm_dev_print, CTLFLAG_RW,
86 &atm_dev_print, 0, "display ATM CPCS headers");
87
88 /*
89 * net.harp.atm.atm_print_data
90 */
91 int atm_print_data;
92 SYSCTL_INT(_net_harp_atm, OID_AUTO, atm_print_data, CTLFLAG_RW,
93 &atm_print_data, 0, "display ATM CPCS payloads");
94
95 /*
96 * Local functions
97 */
98 static KTimeout_ret atm_timexp(void *);
99 static void atm_intr(struct mbuf *);
100
101 /*
102 * Local variables
103 */
104 static struct atm_time *atm_timeq = NULL;
105 static uma_zone_t atm_stackq_zone;
106
107 /*
108 * Initialize ATM kernel
109 *
110 * Performs any initialization required before things really get underway.
111 * Called from ATM domain initialization or from first registration function
112 * which gets called.
113 *
114 * Arguments:
115 * none
116 *
117 * Returns:
118 * none
119 *
120 */
121 void
122 atm_initialize()
123 {
124 /*
125 * Never called from interrupts, so no locking needed
126 */
127 if (atm_init)
128 return;
129 atm_init = 1;
130
131 atm_attributes_zone = uma_zcreate("atm attributes",
132 sizeof(Atm_attributes), NULL, NULL, NULL, NULL,
133 UMA_ALIGN_PTR, 0);
134 if (atm_attributes_zone == NULL)
135 panic("atm_initialize: unable to create attributes zone");
136
137 atm_stackq_zone = uma_zcreate("atm stackq", sizeof(struct stackq_entry),
138 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
139 if (atm_stackq_zone == NULL)
140 panic("atm_initialize: unable to create stackq zone");
141
142 atm_intrq.ifq_maxlen = ATM_INTRQ_MAX;
143 mtx_init(&atm_intrq.ifq_mtx, "atm_inq", NULL, MTX_DEF);
144 netisr_register(NETISR_ATM, atm_intr, &atm_intrq, 0);
145
146 /*
147 * Initialize subsystems
148 */
149 atm_sock_init();
150 atm_cm_init();
151 atm_aal5_init();
152
153 /*
154 * Prime the timer
155 */
156 (void)timeout(atm_timexp, (void *)0, hz/ATM_HZ);
157 }
158
159
160 /*
161 * Handle timer tick expiration
162 *
163 * Decrement tick count in first block on timer queue. If there
164 * are blocks with expired timers, call their timeout function.
165 * This function is called ATM_HZ times per second.
166 *
167 * Arguments:
168 * arg argument passed on timeout() call
169 *
170 * Returns:
171 * none
172 *
173 */
174 static KTimeout_ret
175 atm_timexp(arg)
176 void *arg;
177 {
178 struct atm_time *tip;
179 int s = splimp();
180
181
182 /*
183 * Decrement tick count
184 */
185 if (((tip = atm_timeq) == NULL) || (--tip->ti_ticks > 0)) {
186 goto restart;
187 }
188
189 /*
190 * Stack queue should have been drained
191 */
192 KASSERT(atm_stackq_head == NULL, ("atm_timexp: stack queue not empty"));
193
194 /*
195 * Dispatch expired timers
196 */
197 while (((tip = atm_timeq) != NULL) && (tip->ti_ticks == 0)) {
198 void (*func)(struct atm_time *);
199
200 /*
201 * Remove expired block from queue
202 */
203 atm_timeq = tip->ti_next;
204 tip->ti_flag &= ~TIF_QUEUED;
205
206 /*
207 * Call timeout handler (with network interrupts locked out)
208 */
209 func = tip->ti_func;
210 (void) splx(s);
211 s = splnet();
212 (*func)(tip);
213 (void) splx(s);
214 s = splimp();
215
216 /*
217 * Drain any deferred calls
218 */
219 STACK_DRAIN();
220 }
221
222 restart:
223 /*
224 * Restart the timer
225 */
226 (void) splx(s);
227 (void) timeout(atm_timexp, (void *)0, hz/ATM_HZ);
228
229 return;
230 }
231
232
233 /*
234 * Schedule a control block timeout
235 *
236 * Place the supplied timer control block on the timer queue. The
237 * function (func) will be called in 't' timer ticks with the
238 * control block address as its only argument. There are ATM_HZ
239 * timer ticks per second. The ticks value stored in each block is
240 * a delta of the number of ticks from the previous block in the queue.
241 * Thus, for each tick interval, only the first block in the queue
242 * needs to have its tick value decremented.
243 *
244 * Arguments:
245 * tip pointer to timer control block
246 * t number of timer ticks until expiration
247 * func pointer to function to call at expiration
248 *
249 * Returns:
250 * none
251 *
252 */
253 void
254 atm_timeout(tip, t, func)
255 struct atm_time *tip;
256 int t;
257 void (*func)(struct atm_time *);
258 {
259 struct atm_time *tip1, *tip2;
260 int s;
261
262
263 /*
264 * Check for double queueing error
265 */
266 if (tip->ti_flag & TIF_QUEUED)
267 panic("atm_timeout: double queueing");
268
269 /*
270 * Make sure we delay at least a little bit
271 */
272 if (t <= 0)
273 t = 1;
274
275 /*
276 * Find out where we belong on the queue
277 */
278 s = splimp();
279 for (tip1 = NULL, tip2 = atm_timeq; tip2 && (tip2->ti_ticks <= t);
280 tip1 = tip2, tip2 = tip1->ti_next) {
281 t -= tip2->ti_ticks;
282 }
283
284 /*
285 * Place ourselves on queue and update timer deltas
286 */
287 if (tip1 == NULL)
288 atm_timeq = tip;
289 else
290 tip1->ti_next = tip;
291 tip->ti_next = tip2;
292
293 if (tip2)
294 tip2->ti_ticks -= t;
295
296 /*
297 * Setup timer block
298 */
299 tip->ti_flag |= TIF_QUEUED;
300 tip->ti_ticks = t;
301 tip->ti_func = func;
302
303 (void) splx(s);
304 return;
305 }
306
307
308 /*
309 * Cancel a timeout
310 *
311 * Remove the supplied timer control block from the timer queue.
312 *
313 * Arguments:
314 * tip pointer to timer control block
315 *
316 * Returns:
317 * 0 control block successfully dequeued
318 * 1 control block not on timer queue
319 *
320 */
321 int
322 atm_untimeout(tip)
323 struct atm_time *tip;
324 {
325 struct atm_time *tip1, *tip2;
326 int s;
327
328 /*
329 * Is control block queued?
330 */
331 if ((tip->ti_flag & TIF_QUEUED) == 0)
332 return(1);
333
334 /*
335 * Find control block on the queue
336 */
337 s = splimp();
338 for (tip1 = NULL, tip2 = atm_timeq; tip2 && (tip2 != tip);
339 tip1 = tip2, tip2 = tip1->ti_next) {
340 }
341
342 if (tip2 == NULL) {
343 (void) splx(s);
344 return (1);
345 }
346
347 /*
348 * Remove block from queue and update timer deltas
349 */
350 tip2 = tip->ti_next;
351 if (tip1 == NULL)
352 atm_timeq = tip2;
353 else
354 tip1->ti_next = tip2;
355
356 if (tip2)
357 tip2->ti_ticks += tip->ti_ticks;
358
359 /*
360 * Reset timer block
361 */
362 tip->ti_flag &= ~TIF_QUEUED;
363
364 (void) splx(s);
365 return (0);
366 }
367
368
369 /*
370 * Queue a Stack Call
371 *
372 * Queues a stack call which must be deferred to the global stack queue.
373 * The call parameters are stored in entries which are allocated from the
374 * stack queue storage pool.
375 *
376 * Arguments:
377 * cmd stack command
378 * func destination function
379 * token destination layer's token
380 * cvp pointer to connection vcc
381 * arg1 command argument
382 * arg2 command argument
383 *
384 * Returns:
385 * 0 call queued
386 * errno call not queued - reason indicated
387 *
388 */
389 int
390 atm_stack_enq(cmd, func, token, cvp, arg1, arg2)
391 int cmd;
392 void (*func)(int, void *, intptr_t, intptr_t);
393 void *token;
394 Atm_connvc *cvp;
395 intptr_t arg1;
396 intptr_t arg2;
397 {
398 struct stackq_entry *sqp;
399 int s = splnet();
400
401 /*
402 * Get a new queue entry for this call
403 */
404 sqp = uma_zalloc(atm_stackq_zone, M_NOWAIT | M_ZERO);
405 if (sqp == NULL) {
406 (void) splx(s);
407 return (ENOMEM);
408 }
409
410 /*
411 * Fill in new entry
412 */
413 sqp->sq_next = NULL;
414 sqp->sq_cmd = cmd;
415 sqp->sq_func = func;
416 sqp->sq_token = token;
417 sqp->sq_arg1 = arg1;
418 sqp->sq_arg2 = arg2;
419 sqp->sq_connvc = cvp;
420
421 /*
422 * Put new entry at end of queue
423 */
424 if (atm_stackq_head == NULL)
425 atm_stackq_head = sqp;
426 else
427 atm_stackq_tail->sq_next = sqp;
428 atm_stackq_tail = sqp;
429
430 (void) splx(s);
431 return (0);
432 }
433
434
435 /*
436 * Drain the Stack Queue
437 *
438 * Dequeues and processes entries from the global stack queue.
439 *
440 * Arguments:
441 * none
442 *
443 * Returns:
444 * none
445 *
446 */
447 void
448 atm_stack_drain()
449 {
450 struct stackq_entry *sqp, *qprev, *qnext;
451 int s = splnet();
452 int cnt;
453
454 /*
455 * Loop thru entire queue until queue is empty
456 * (but panic rather loop forever)
457 */
458 do {
459 cnt = 0;
460 qprev = NULL;
461 for (sqp = atm_stackq_head; sqp; ) {
462
463 /*
464 * Got an eligible entry, do STACK_CALL stuff
465 */
466 if (sqp->sq_cmd & STKCMD_UP) {
467 if (sqp->sq_connvc->cvc_downcnt) {
468
469 /*
470 * Cant process now, skip it
471 */
472 qprev = sqp;
473 sqp = sqp->sq_next;
474 continue;
475 }
476
477 /*
478 * OK, dispatch the call
479 */
480 sqp->sq_connvc->cvc_upcnt++;
481 (*sqp->sq_func)(sqp->sq_cmd,
482 sqp->sq_token,
483 sqp->sq_arg1,
484 sqp->sq_arg2);
485 sqp->sq_connvc->cvc_upcnt--;
486 } else {
487 if (sqp->sq_connvc->cvc_upcnt) {
488
489 /*
490 * Cant process now, skip it
491 */
492 qprev = sqp;
493 sqp = sqp->sq_next;
494 continue;
495 }
496
497 /*
498 * OK, dispatch the call
499 */
500 sqp->sq_connvc->cvc_downcnt++;
501 (*sqp->sq_func)(sqp->sq_cmd,
502 sqp->sq_token,
503 sqp->sq_arg1,
504 sqp->sq_arg2);
505 sqp->sq_connvc->cvc_downcnt--;
506 }
507
508 /*
509 * Dequeue processed entry and free it
510 */
511 cnt++;
512 qnext = sqp->sq_next;
513 if (qprev)
514 qprev->sq_next = qnext;
515 else
516 atm_stackq_head = qnext;
517 if (qnext == NULL)
518 atm_stackq_tail = qprev;
519 uma_zfree(atm_stackq_zone, sqp);
520 sqp = qnext;
521 }
522 } while (cnt > 0);
523
524 /*
525 * Make sure entire queue was drained
526 */
527 if (atm_stackq_head != NULL)
528 panic("atm_stack_drain: Queue not emptied");
529
530 (void) splx(s);
531 }
532
533
534 /*
535 * Process Interrupt Queue
536 *
537 * Processes entries on the ATM interrupt queue. This queue is used by
538 * device interface drivers in order to schedule events from the driver's
539 * lower (interrupt) half to the driver's stack services.
540 *
541 * The interrupt routines must store the stack processing function to call
542 * and a token (typically a driver/stack control block) at the front of the
543 * queued buffer. We assume that the function pointer and token values are
544 * both contained (and properly aligned) in the first buffer of the chain.
545 * The size of these two fields is not accounted for in the packet header
546 * length field. The packet header itself must be in the first mbuf.
547 *
548 * Arguments:
549 * none
550 *
551 * Returns:
552 * none
553 *
554 */
555 static void
556 atm_intr(struct mbuf *m)
557 {
558 caddr_t cp;
559 atm_intr_func_t func;
560 void *token;
561
562 GIANT_REQUIRED;
563
564 /*
565 * Get function to call and token value
566 */
567 cp = mtod(m, caddr_t);
568 func = *(atm_intr_func_t *)cp;
569 cp += sizeof(func);
570 token = *(void **)cp;
571
572 m->m_len -= sizeof(func) + sizeof(token);
573 m->m_data += sizeof(func) + sizeof(token);
574
575 /*
576 * Call processing function
577 */
578 (*func)(token, m);
579
580 /*
581 * Drain any deferred calls
582 */
583 STACK_DRAIN();
584 }
585
586 /*
587 * Print a pdu buffer chain
588 *
589 * Arguments:
590 * m pointer to pdu buffer chain
591 * msg pointer to message header string
592 *
593 * Returns:
594 * none
595 *
596 */
597 void
598 atm_pdu_print(const KBuffer *m, const char *msg)
599 {
600 const u_char *cp;
601 int i;
602 char c = ' ';
603
604 printf("%s:", msg);
605 while (m) {
606 KB_DATASTART(m, cp, const u_char *);
607 printf("%cbfr=%p data=%p len=%d: ",
608 c, m, cp, KB_LEN(m));
609 c = '\t';
610 if (atm_print_data) {
611 for (i = 0; i < KB_LEN(m); i++) {
612 printf("%2x ", *cp++);
613 }
614 printf("<end_bfr>\n");
615 } else {
616 printf("\n");
617 }
618 m = KB_NEXT(m);
619 }
620 }
Cache object: 2a1f3fe4fb830555016e08186c84b95e
|