2 * ===================================
3 * HARP | Host ATM Research Platform
4 * ===================================
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.
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.
20 * Copyright 1994-1998 Network Computing Services, Inc.
22 * Copies of this Software may be made, however, the above copyright
23 * notice must be reproduced on all copies.
30 * Miscellaneous ATM subroutines
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/errno.h>
39 #include <sys/malloc.h>
41 #include <sys/kernel.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/sysctl.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>
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 } };
68 int atm_version = ATM_VERSION;
69 struct timeval atm_debugtime = {0, 0};
70 struct ifqueue atm_intrq;
72 uma_zone_t atm_attributes_zone;
75 * net.harp.atm.atm_debug
78 SYSCTL_INT(_net_harp_atm, OID_AUTO, atm_debug, CTLFLAG_RW,
79 &atm_debug, 0, "HARP ATM layer debugging flag");
82 * net.harp.atm.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");
89 * net.harp.atm.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");
98 static KTimeout_ret atm_timexp(void *);
99 static void atm_intr(struct mbuf *);
104 static struct atm_time *atm_timeq = NULL;
105 static uma_zone_t atm_stackq_zone;
108 * Initialize ATM kernel
110 * Performs any initialization required before things really get underway.
111 * Called from ATM domain initialization or from first registration function
125 * Never called from interrupts, so no locking needed
131 atm_attributes_zone = uma_zcreate("atm attributes",
132 sizeof(Atm_attributes), NULL, NULL, NULL, NULL,
134 if (atm_attributes_zone == NULL)
135 panic("atm_initialize: unable to create attributes zone");
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");
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);
147 * Initialize subsystems
156 (void)timeout(atm_timexp, (void *)0, hz/ATM_HZ);
161 * Handle timer tick expiration
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.
168 * arg argument passed on timeout() call
178 struct atm_time *tip;
183 * Decrement tick count
185 if (((tip = atm_timeq) == NULL) || (--tip->ti_ticks > 0)) {
190 * Stack queue should have been drained
192 KASSERT(atm_stackq_head == NULL, ("atm_timexp: stack queue not empty"));
195 * Dispatch expired timers
197 while (((tip = atm_timeq) != NULL) && (tip->ti_ticks == 0)) {
198 void (*func)(struct atm_time *);
201 * Remove expired block from queue
203 atm_timeq = tip->ti_next;
204 tip->ti_flag &= ~TIF_QUEUED;
207 * Call timeout handler (with network interrupts locked out)
217 * Drain any deferred calls
227 (void) timeout(atm_timexp, (void *)0, hz/ATM_HZ);
234 * Schedule a control block timeout
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.
245 * tip pointer to timer control block
246 * t number of timer ticks until expiration
247 * func pointer to function to call at expiration
254 atm_timeout(tip, t, func)
255 struct atm_time *tip;
257 void (*func)(struct atm_time *);
259 struct atm_time *tip1, *tip2;
264 * Check for double queueing error
266 if (tip->ti_flag & TIF_QUEUED)
267 panic("atm_timeout: double queueing");
270 * Make sure we delay at least a little bit
276 * Find out where we belong on the queue
279 for (tip1 = NULL, tip2 = atm_timeq; tip2 && (tip2->ti_ticks <= t);
280 tip1 = tip2, tip2 = tip1->ti_next) {
285 * Place ourselves on queue and update timer deltas
299 tip->ti_flag |= TIF_QUEUED;
311 * Remove the supplied timer control block from the timer queue.
314 * tip pointer to timer control block
317 * 0 control block successfully dequeued
318 * 1 control block not on timer queue
323 struct atm_time *tip;
325 struct atm_time *tip1, *tip2;
329 * Is control block queued?
331 if ((tip->ti_flag & TIF_QUEUED) == 0)
335 * Find control block on the queue
338 for (tip1 = NULL, tip2 = atm_timeq; tip2 && (tip2 != tip);
339 tip1 = tip2, tip2 = tip1->ti_next) {
348 * Remove block from queue and update timer deltas
354 tip1->ti_next = tip2;
357 tip2->ti_ticks += tip->ti_ticks;
362 tip->ti_flag &= ~TIF_QUEUED;
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.
378 * func destination function
379 * token destination layer's token
380 * cvp pointer to connection vcc
381 * arg1 command argument
382 * arg2 command argument
386 * errno call not queued - reason indicated
390 atm_stack_enq(cmd, func, token, cvp, arg1, arg2)
392 void (*func)(int, void *, intptr_t, intptr_t);
398 struct stackq_entry *sqp;
402 * Get a new queue entry for this call
404 sqp = uma_zalloc(atm_stackq_zone, M_NOWAIT | M_ZERO);
416 sqp->sq_token = token;
419 sqp->sq_connvc = cvp;
422 * Put new entry at end of queue
424 if (atm_stackq_head == NULL)
425 atm_stackq_head = sqp;
427 atm_stackq_tail->sq_next = sqp;
428 atm_stackq_tail = sqp;
436 * Drain the Stack Queue
438 * Dequeues and processes entries from the global stack queue.
450 struct stackq_entry *sqp, *qprev, *qnext;
455 * Loop thru entire queue until queue is empty
456 * (but panic rather loop forever)
461 for (sqp = atm_stackq_head; sqp; ) {
464 * Got an eligible entry, do STACK_CALL stuff
466 if (sqp->sq_cmd & STKCMD_UP) {
467 if (sqp->sq_connvc->cvc_downcnt) {
470 * Cant process now, skip it
478 * OK, dispatch the call
480 sqp->sq_connvc->cvc_upcnt++;
481 (*sqp->sq_func)(sqp->sq_cmd,
485 sqp->sq_connvc->cvc_upcnt--;
487 if (sqp->sq_connvc->cvc_upcnt) {
490 * Cant process now, skip it
498 * OK, dispatch the call
500 sqp->sq_connvc->cvc_downcnt++;
501 (*sqp->sq_func)(sqp->sq_cmd,
505 sqp->sq_connvc->cvc_downcnt--;
509 * Dequeue processed entry and free it
512 qnext = sqp->sq_next;
514 qprev->sq_next = qnext;
516 atm_stackq_head = qnext;
518 atm_stackq_tail = qprev;
519 uma_zfree(atm_stackq_zone, sqp);
525 * Make sure entire queue was drained
527 if (atm_stackq_head != NULL)
528 panic("atm_stack_drain: Queue not emptied");
535 * Process Interrupt Queue
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.
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.
556 atm_intr(struct mbuf *m)
559 atm_intr_func_t func;
565 * Get function to call and token value
567 cp = mtod(m, caddr_t);
568 func = *(atm_intr_func_t *)cp;
570 token = *(void **)cp;
572 m->m_len -= sizeof(func) + sizeof(token);
573 m->m_data += sizeof(func) + sizeof(token);
576 * Call processing function
581 * Drain any deferred calls
587 * Print a pdu buffer chain
590 * m pointer to pdu buffer chain
591 * msg pointer to message header string
598 atm_pdu_print(const KBuffer *m, const char *msg)
606 KB_DATASTART(m, cp, const u_char *);
607 printf("%cbfr=%p data=%p len=%d: ",
608 c, m, cp, KB_LEN(m));
610 if (atm_print_data) {
611 for (i = 0; i < KB_LEN(m); i++) {
612 printf("%2x ", *cp++);
614 printf("<end_bfr>\n");