]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netatm/atm_subr.c
This commit was generated by cvs2svn to compensate for changes in r153877,
[FreeBSD/FreeBSD.git] / 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 }