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 }
Cache object: 8769371286b1077e0242c81530c23643
|