]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netatm/atm_device.c
This commit was generated by cvs2svn to compensate for changes in r162852,
[FreeBSD/FreeBSD.git] / sys / netatm / atm_device.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  * ATM device support functions
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/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/syslog.h>
44 #include <net/if.h>
45 #include <net/bpf.h>
46 #include <netatm/port.h>
47 #include <netatm/queue.h>
48 #include <netatm/atm.h>
49 #include <netatm/atm_sys.h>
50 #include <netatm/atm_sap.h>
51 #include <netatm/atm_cm.h>
52 #include <netatm/atm_if.h>
53 #include <netatm/atm_vc.h>
54 #include <netatm/atm_stack.h>
55 #include <netatm/atm_pcb.h>
56 #include <netatm/atm_var.h>
57
58 /*
59  * Private structures for managing allocated kernel memory resources
60  *
61  * For each allocation of kernel memory, one Mem_ent will be used.  
62  * The Mem_ent structures will be allocated in blocks inside of a 
63  * Mem_blk structure.
64  */
65 #define MEM_NMEMENT     10              /* How many Mem_ent's in a Mem_blk */
66
67 struct mem_ent {
68         void            *me_kaddr;      /* Allocated memory address */
69         u_int           me_ksize;       /* Allocated memory length */
70         void            *me_uaddr;      /* Memory address returned to caller */
71         u_int           me_flags;       /* Flags (see below) */
72 };
73 typedef struct mem_ent  Mem_ent;
74
75 /*
76  * Memory entry flags
77  */
78 #define MEF_NONCACHE    1               /* Memory is noncacheable */
79
80
81 struct mem_blk {
82         struct mem_blk  *mb_next;       /* Next block in chain */
83         Mem_ent         mb_mement[MEM_NMEMENT]; /* Allocated memory entries */
84 };
85 typedef struct mem_blk  Mem_blk;
86
87 static Mem_blk          *atm_mem_head = NULL;
88
89 static struct t_atm_cause       atm_dev_cause = {
90         T_ATM_ITU_CODING,
91         T_ATM_LOC_USER,
92         T_ATM_CAUSE_VPCI_VCI_ASSIGNMENT_FAILURE,
93         {0, 0, 0, 0}
94 };
95
96 extern struct ifqueue atm_intrq;
97
98 /*
99  * ATM Device Stack Instantiation
100  *
101  * Called at splnet.
102  *
103  * Arguments
104  *      ssp             pointer to array of stack definition pointers
105  *                      for connection
106  *                      ssp[0] points to upper layer's stack definition
107  *                      ssp[1] points to this layer's stack definition
108  *                      ssp[2] points to lower layer's stack definition
109  *      cvcp            pointer to connection vcc for this stack
110  *
111  * Returns
112  *      0               instantiation successful
113  *      err             instantiation failed - reason indicated
114  *
115  */
116 int
117 atm_dev_inst(ssp, cvcp)
118         struct stack_defn       **ssp;
119         Atm_connvc              *cvcp;
120 {
121         Cmn_unit        *cup = (Cmn_unit *)cvcp->cvc_attr.nif->nif_pif;
122         Cmn_vcc         *cvp;
123         int             err;
124
125         /*
126          * Check to see if device has been initialized
127          */
128         if ((cup->cu_flags & CUF_INITED) == 0)
129                 return ( EIO );
130
131         /*
132          * Validate lower SAP
133          */
134         /*
135          * Device driver is the lowest layer - no need to validate
136          */
137
138         /*
139          * Validate PVC vpi.vci
140          */
141         if (cvcp->cvc_attr.called.addr.address_format == T_ATM_PVC_ADDR) {
142                 /*
143                  * Look through existing circuits - return error if found
144                  */
145                 Atm_addr_pvc    *pp;
146
147                 pp = (Atm_addr_pvc *)cvcp->cvc_attr.called.addr.address;
148                 if (atm_dev_vcc_find(cup, ATM_PVC_GET_VPI(pp),
149                                 ATM_PVC_GET_VCI(pp), 0))
150                         return ( EADDRINUSE );
151         }
152
153         /*
154          * Validate our SAP type
155          */
156         switch ((*(ssp+1))->sd_sap) {
157         case SAP_CPCS_AAL3_4:
158         case SAP_CPCS_AAL5:
159         case SAP_ATM:
160                 break;
161         default:
162                 return (EINVAL);
163         }
164
165         /*
166          * Allocate a VCC control block
167          * This can happen from a callout so don't wait here.
168          */
169         cvp = uma_zalloc(cup->cu_vcc_zone, M_NOWAIT);
170         if (cvp == NULL)
171                 return (ENOMEM);
172         
173         cvp->cv_state = CVS_INST;
174         cvp->cv_toku = (*ssp)->sd_toku;
175         cvp->cv_upper = (*ssp)->sd_upper;
176         cvp->cv_connvc = cvcp;
177
178         /*
179          * Let device have a look at the connection request
180          */
181         err = (*cup->cu_instvcc)(cup, cvp);
182         if (err) {
183                 uma_zfree(cup->cu_vcc_zone, cvp);
184                 return (err);
185         }
186
187         /*
188          * Looks good so far, so link in device VCC
189          */
190         LINK2TAIL ( cvp, Cmn_vcc, cup->cu_vcc, cv_next );
191
192         /*
193          * Save my token
194          */
195         (*++ssp)->sd_toku = cvp;
196
197         /*
198          * Pass instantiation down the stack
199          */
200         /*
201          * No need - we're the lowest point.
202          */
203         /* err = (*(ssp + 1))->sd_inst(ssp, cvcp); */
204
205         /*
206          * Save the lower layer's interface info
207          */
208         /*
209          * No need - we're the lowest point
210          */
211         /* cvp->cv_lower = (*++ssp)->sd_lower; */
212         /* cvp->cv_tok1 = (*ssp)->sd_toku; */
213
214         return (0);
215 }
216
217
218 /*
219  * ATM Device Stack Command Handler
220  *
221  * Arguments
222  *      cmd             stack command code
223  *      tok             session token (Cmn_vcc)
224  *      arg1            command specific argument
225  *      arg2            command specific argument
226  *
227  * Returns
228  *      none
229  *
230  */
231 /*ARGSUSED*/
232 void
233 atm_dev_lower(cmd, tok, arg1, arg2)
234         int     cmd;
235         void    *tok;
236         intptr_t        arg1;
237         intptr_t        arg2;
238 {
239         Cmn_vcc         *cvp = (Cmn_vcc *)tok;
240         Atm_connvc      *cvcp = cvp->cv_connvc;
241         Cmn_unit        *cup = (Cmn_unit *)cvcp->cvc_attr.nif->nif_pif;
242         struct vccb     *vcp;
243         u_int           state;
244         int             s;
245
246         switch ( cmd ) {
247
248         case CPCS_INIT:
249                 /*
250                  * Sanity check
251                  */
252                 if ( cvp->cv_state != CVS_INST ) {
253                         log ( LOG_ERR,
254                                 "atm_dev_lower: INIT: tok=%p, state=%d\n",
255                                 tok, cvp->cv_state );
256                         break;
257                 }
258
259                 vcp = cvp->cv_connvc->cvc_vcc;
260
261                 /*
262                  * Validate SVC vpi.vci
263                  */
264                 if ( vcp->vc_type & VCC_SVC ) {
265
266                         if (atm_dev_vcc_find(cup, vcp->vc_vpi, vcp->vc_vci,
267                                         vcp->vc_type & (VCC_IN | VCC_OUT))
268                                                 != cvp){
269                                 log ( LOG_ERR,
270                                   "atm_dev_lower: dup SVC (%d,%d) tok=%p\n",
271                                         vcp->vc_vpi, vcp->vc_vci, tok );
272                                 atm_cm_abort(cvp->cv_connvc, &atm_dev_cause);
273                                 break;
274                         }
275                 }
276
277                 /*
278                  * Tell the device to open the VCC
279                  */
280                 cvp->cv_state = CVS_INITED;
281                 s = splimp();
282                 if ((*cup->cu_openvcc)(cup, cvp)) {
283                         atm_cm_abort(cvp->cv_connvc, &atm_dev_cause);
284                         (void) splx(s);
285                         break;
286                 }
287                 (void) splx(s);
288                 break;
289
290         case CPCS_TERM: {
291                 KBuffer         *m, *prev, *next;
292                 int             *ip;
293
294                 s = splimp();
295
296                 /*
297                  * Disconnect the VCC - ignore return code
298                  */
299                 if ((cvp->cv_state == CVS_INITED) || 
300                     (cvp->cv_state == CVS_ACTIVE)) {
301                         (void) (*cup->cu_closevcc)(cup, cvp);
302                 }
303                 cvp->cv_state = CVS_TERM;
304
305                 /*
306                  * Remove from interface list
307                  */
308                 UNLINK ( cvp, Cmn_vcc, cup->cu_vcc, cv_next );
309
310                 /*
311                  * Free any buffers from this VCC on the ATM interrupt queue
312                  */
313                 prev = NULL;
314                 IF_LOCK(&atm_intrq);
315                 for (m = atm_intrq.ifq_head; m; m = next) {
316                         next = KB_QNEXT(m);
317
318                         /*
319                          * See if this entry is for the terminating VCC
320                          */
321                         KB_DATASTART(m, ip, int *);
322                         ip++;
323                         if (*ip == (intptr_t)cvp) {
324                                 /*
325                                  * Yep, so dequeue the entry
326                                  */
327                                 if (prev == NULL)
328                                         atm_intrq.ifq_head = next;
329                                 else
330                                         KB_QNEXT(prev) = next;
331
332                                 if (next == NULL)
333                                         atm_intrq.ifq_tail = prev;
334
335                                 atm_intrq.ifq_len--;
336
337                                 /*
338                                  * Free the unwanted buffers
339                                  */
340                                 KB_FREEALL(m);
341                         } else {
342                                 prev = m;
343                         }
344                 }
345                 IF_UNLOCK(&atm_intrq);
346                 (void) splx(s);
347
348                 /*
349                  * Free VCC resources
350                  */
351                 uma_zfree(cup->cu_vcc_zone, cvp);
352                 break;
353                 }
354
355         case CPCS_UNITDATA_INV:
356
357                 /*
358                  * Sanity check
359                  *
360                  * Use temp state variable since we dont want to lock out
361                  * interrupts, but initial VC activation interrupt may
362                  * happen here, changing state somewhere in the middle.
363                  */
364                 state = cvp->cv_state;
365                 if ((state != CVS_ACTIVE) && 
366                     (state != CVS_INITED)) {
367                         log ( LOG_ERR,
368                             "atm_dev_lower: UNITDATA: tok=%p, state=%d\n",
369                                 tok, state );
370                         KB_FREEALL((KBuffer *)arg1);
371                         break;
372                 }
373
374                 /*
375                  * Send the packet to the interface's bpf if this vc has one.
376                  */
377                 if (cvcp->cvc_vcc != NULL && cvcp->cvc_vcc->vc_nif != NULL) {
378                         struct ifnet *ifp =
379                             (struct ifnet *)cvcp->cvc_vcc->vc_nif;
380
381                         BPF_MTAP(ifp, (KBuffer *)arg1);
382                 }
383
384                 /*
385                  * Hand the data off to the device
386                  */
387                 (*cup->cu_output)(cup, cvp, (KBuffer *)arg1);
388
389                 break;
390
391         case CPCS_UABORT_INV:
392                 log ( LOG_ERR,
393                     "atm_dev_lower: unimplemented stack cmd 0x%x, tok=%p\n",
394                         cmd, tok );
395                 break;
396
397         default:
398                 log ( LOG_ERR,
399                         "atm_dev_lower: unknown stack cmd 0x%x, tok=%p\n",
400                         cmd, tok );
401
402         }
403
404         return;
405 }
406
407
408
409 /*
410  * Allocate kernel memory block
411  * 
412  * This function will allocate a kernel memory block of the type specified
413  * in the flags parameter.  The returned address will point to a memory
414  * block of the requested size and alignment.  The memory block will also 
415  * be zeroed.  The alloc/free functions will manage/mask both the OS-specific 
416  * kernel memory management requirements and the bookkeeping required to
417  * deal with data alignment issues. 
418  *
419  * This function should not be called from interrupt level.
420  *
421  * Arguments:
422  *      size    size of memory block to allocate
423  *      align   data alignment requirement 
424  *      flags   allocation flags (ATM_DEV_*)
425  *
426  * Returns:
427  *      uaddr   pointer to aligned memory block
428  *      NULL    unable to allocate memory
429  *
430  */
431 void *         
432 atm_dev_alloc(size, align, flags)
433         u_int           size;
434         u_int           align;
435         u_int           flags;
436 {
437         Mem_blk         *mbp;
438         Mem_ent         *mep;
439         u_int           kalign, ksize;
440         int             s, i;
441
442         s = splimp();
443
444         /*
445          * Find a free Mem_ent
446          */
447         mep = NULL;
448         for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) {
449                 for (i = 0; i < MEM_NMEMENT; i++) {
450                         if (mbp->mb_mement[i].me_uaddr == NULL) {
451                                 mep = &mbp->mb_mement[i];
452                                 break;
453                         }
454                 }
455         }
456
457         /*
458          * If there are no free Mem_ent's, then allocate a new Mem_blk
459          * and link it into the chain
460          */
461         if (mep == NULL) {
462                 mbp = malloc(sizeof(Mem_blk), M_DEVBUF, M_NOWAIT|M_ZERO);
463                 if (mbp == NULL) {
464                         log(LOG_ERR, "atm_dev_alloc: Mem_blk failure\n");
465                         (void) splx(s);
466                         return (NULL);
467                 }
468                 mbp->mb_next = atm_mem_head;
469                 atm_mem_head = mbp;
470                 mep = mbp->mb_mement;
471         }
472
473         /*
474          * Now we need to get the kernel's allocation alignment minimum
475          *
476          * This is obviously very OS-specific stuff
477          */
478         kalign = MINALLOCSIZE;
479
480         /*
481          * Figure out how much memory we must allocate to satify the
482          * user's size and alignment needs
483          */
484         if (align <= kalign)
485                 ksize = size;
486         else
487                 ksize = size + align - kalign;
488
489         /*
490          * Finally, go get the memory
491          */
492         if (flags & ATM_DEV_NONCACHE) {
493                 mep->me_kaddr = malloc(ksize, M_DEVBUF, M_NOWAIT);
494         } else {
495                 mep->me_kaddr = malloc(ksize, M_DEVBUF, M_NOWAIT);
496         }
497
498         if (mep->me_kaddr == NULL) {
499                 log(LOG_ERR, "atm_dev_alloc: %skernel memory unavailable\n",
500                         (flags & ATM_DEV_NONCACHE) ? "non-cacheable " : "");
501                 (void) splx(s);
502                 return (NULL);
503         }
504
505         /*
506          * Calculate correct alignment address to pass back to user
507          */
508         mep->me_uaddr = (void *) roundup((uintptr_t)mep->me_kaddr, align);
509         mep->me_ksize = ksize;
510         mep->me_flags = flags;
511
512         /*
513          * Clear memory for user
514          */
515         bzero(mep->me_uaddr, size);
516
517         ATM_DEBUG4("atm_dev_alloc: size=%d, align=%d, flags=%d, uaddr=%p\n", 
518                 size, align, flags, mep->me_uaddr);
519
520         (void) splx(s);
521
522         return (mep->me_uaddr);
523 }
524
525
526 /*
527  * Free kernel memory block
528  * 
529  * This function will free a kernel memory block previously allocated by
530  * the atm_dev_alloc function.  
531  *
532  * This function should not be called from interrupt level.
533  *
534  * Arguments:
535  *      uaddr   pointer to allocated aligned memory block
536  *
537  * Returns:
538  *      none
539  *
540  */
541 void
542 atm_dev_free(uaddr)
543         volatile void           *uaddr;
544 {
545         Mem_blk         *mbp;
546         Mem_ent         *mep;
547         int             s, i;
548
549         ATM_DEBUG1("atm_dev_free: uaddr=%p\n", uaddr);
550
551         s = splimp();
552
553         /*
554          * Protect ourselves...
555          */
556         if (uaddr == NULL)
557                 panic("atm_dev_free: trying to free null address");
558
559         /*
560          * Find our associated entry
561          */
562         mep = NULL;
563         for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) {
564                 for (i = 0; i < MEM_NMEMENT; i++) {
565                         if (mbp->mb_mement[i].me_uaddr == uaddr) {
566                                 mep = &mbp->mb_mement[i];
567                                 break;
568                         }
569                 }
570         }
571
572         /*
573          * If we didn't find our entry, then unceremoniously let the caller
574          * know they screwed up (it certainly couldn't be a bug here...)
575          */
576         if (mep == NULL)
577                 panic("atm_dev_free: trying to free unknown address");
578         
579         /*
580          * Give the memory space back to the kernel
581          */
582         if (mep->me_flags & ATM_DEV_NONCACHE) {
583                 free(mep->me_kaddr, M_DEVBUF);
584         } else {
585                 free(mep->me_kaddr, M_DEVBUF);
586         }
587
588         /*
589          * Free our entry
590          */
591         mep->me_uaddr = NULL;
592
593         (void) splx(s);
594
595         return;
596 }
597
598 /*
599  * Compress buffer chain
600  * 
601  * This function will compress a supplied buffer chain into a minimum number
602  * of kernel buffers.  Typically, this function will be used because the
603  * number of buffers in an output buffer chain is too large for a device's
604  * DMA capabilities.  This should only be called as a last resort, since
605  * all the data copying will surely kill any hopes of decent performance.
606  *
607  * Arguments:
608  *      m       pointer to source buffer chain
609  *
610  * Returns:
611  *      n       pointer to compressed buffer chain
612  *
613  */
614 KBuffer *         
615 atm_dev_compress(m)
616         KBuffer         *m;
617 {
618         KBuffer         *n, *n0, **np;
619         int             len, space;
620         caddr_t         src, dst;
621
622         n = n0 = NULL;
623         np = &n0;
624         dst = NULL;
625         space = 0;
626
627         /*
628          * Copy each source buffer into compressed chain
629          */
630         while (m) {
631
632                 if (space == 0) {
633
634                         /*
635                          * Allocate another buffer for compressed chain
636                          */
637                         KB_ALLOCEXT(n, ATM_DEV_CMPR_LG, KB_F_NOWAIT, KB_T_DATA);
638                         if (n) {
639                                 space = ATM_DEV_CMPR_LG;
640                         } else {
641                                 KB_ALLOC(n, ATM_DEV_CMPR_SM, KB_F_NOWAIT, 
642                                         KB_T_DATA);
643                                 if (n) {
644                                         space = ATM_DEV_CMPR_SM;
645                                 } else {
646                                         /*
647                                          * Unable to get any new buffers, so
648                                          * just return the partially compressed
649                                          * chain and hope...
650                                          */
651                                         *np = m;
652                                         break;
653                                 }
654                         }
655
656                         KB_HEADSET(n, 0);
657                         KB_LEN(n) = 0;
658                         KB_BFRSTART(n, dst, caddr_t);
659
660                         *np = n;
661                         np = &KB_NEXT(n);
662                 }
663
664                 /*
665                  * Copy what we can from source buffer
666                  */
667                 len = MIN(space, KB_LEN(m));
668                 KB_DATASTART(m, src, caddr_t);
669                 bcopy(src, dst, len);
670
671                 /*
672                  * Adjust for copied data
673                  */
674                 dst += len;
675                 space -= len;
676
677                 KB_HEADADJ(m, -len);
678                 KB_TAILADJ(n, len);
679
680                 /*
681                  * If we've exhausted our current source buffer, free it
682                  * and move to the next one
683                  */
684                 if (KB_LEN(m) == 0) {
685                         KB_FREEONE(m, m);
686                 }
687         }
688
689         return (n0);
690 }
691
692
693 /*
694  * Locate VCC entry
695  * 
696  * This function will return the VCC entry for a specified interface and
697  * VPI/VCI value.
698  *
699  * Arguments:
700  *      cup     pointer to interface unit structure
701  *      vpi     VPI value
702  *      vci     VCI value
703  *      type    VCC type
704  *
705  * Returns:
706  *      vcp     pointer to located VCC entry matching
707  *      NULL    no VCC found
708  *
709  */
710 Cmn_vcc *
711 atm_dev_vcc_find(cup, vpi, vci, type)
712         Cmn_unit        *cup;
713         u_int           vpi;
714         u_int           vci;
715         u_int           type;
716 {
717         Cmn_vcc         *cvp;
718         int             s = splnet();
719
720         /*
721          * Go find VCC
722          *
723          * (Probably should stick in a hash table some time)
724          */
725         for (cvp = cup->cu_vcc; cvp; cvp = cvp->cv_next) {
726                 struct vccb     *vcp;
727
728                 vcp = cvp->cv_connvc->cvc_vcc;
729                 if ((vcp->vc_vci == vci) && (vcp->vc_vpi == vpi) && 
730                     ((vcp->vc_type & type) == type))
731                         break;
732         }
733
734         (void) splx(s);
735         return (cvp);
736 }
737
738
739 #ifdef notdef
740 /*
741  * Module unloading notification
742  * 
743  * This function must be called just prior to unloading the module from 
744  * memory.  All allocated memory will be freed here and anything else that
745  * needs cleaning up.
746  *
747  * Arguments:
748  *      none
749  *
750  * Returns:
751  *      none
752  *
753  */
754 void
755 atm_unload()
756 {
757         Mem_blk         *mbp;
758         Mem_ent         *mep;
759         int             s, i;
760
761         s = splimp();
762
763         /*
764          * Free up all of our memory management storage
765          */
766         while (mbp = atm_mem_head) {
767
768                 /*
769                  * Make sure users have freed up all of their memory
770                  */
771                 for (i = 0; i < MEM_NMEMENT; i++) {
772                         if (mbp->mb_mement[i].me_uaddr != NULL) {
773                                 panic("atm_unload: unfreed memory");
774                         }
775                 }
776
777                 atm_mem_head = mbp->mb_next;
778
779                 /*
780                  * Hand this block back to the kernel
781                  */
782                 free((caddr_t)mbp, M_DEVBUF);
783         }
784
785         (void) splx(s);
786
787         return;
788 }
789 #endif  /* notdef */
790
791
792 /*
793  * Print a PDU
794  * 
795  * Arguments:
796  *      cup     pointer to device unit
797  *      cvp     pointer to VCC control block
798  *      m       pointer to pdu buffer chain
799  *      msg     pointer to message string
800  *
801  * Returns:
802  *      none
803  *
804  */
805 void
806 atm_dev_pdu_print(const Cmn_unit *cup, const Cmn_vcc *cvp,
807     const KBuffer *m, const char *msg)
808 {
809         char            buf[128];
810
811         snprintf(buf, sizeof(buf), "%s vcc=(%d,%d)", msg, 
812                 cvp->cv_connvc->cvc_vcc->vc_vpi, 
813                 cvp->cv_connvc->cvc_vcc->vc_vci);
814
815         atm_pdu_print(m, buf);
816 }