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.
27 * ATM Forum UNI 3.0/3.1 Signalling Manager
28 * ----------------------------------------
30 * System interface module
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/types.h>
39 #include <sys/errno.h>
40 #include <sys/malloc.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/syslog.h>
46 #include <netinet/in.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_vc.h>
55 #include <netatm/atm_ioctl.h>
56 #include <netatm/atm_sigmgr.h>
57 #include <netatm/atm_stack.h>
58 #include <netatm/atm_pcb.h>
59 #include <netatm/atm_var.h>
61 #include <netatm/ipatm/ipatm_var.h>
62 #include <netatm/ipatm/ipatm_serv.h>
63 #include <netatm/uni/uniip_var.h>
65 #include <netatm/uni/unisig.h>
66 #include <netatm/uni/unisig_var.h>
67 #include <netatm/uni/unisig_msg.h>
74 uma_zone_t unisig_vc_zone;
75 uma_zone_t unisig_msg_zone;
76 uma_zone_t unisig_ie_zone;
81 static int unisig_attach(struct sigmgr *, struct atm_pif *);
82 static int unisig_detach(struct atm_pif *);
83 static int unisig_setup(Atm_connvc *, int *);
84 static int unisig_release(struct vccb *, int *);
85 static int unisig_accept(struct vccb *, int *);
86 static int unisig_reject(struct vccb *, int *);
87 static int unisig_abort(struct vccb *);
88 static int unisig_ioctl(int, caddr_t, caddr_t);
94 static struct sigmgr unisig_mgr30 = {
108 static struct sigmgr unisig_mgr31 = {
124 * Initialize UNISIG processing
126 * This will be called during module loading. We'll just register
127 * the UNISIG protocol descriptor and wait for a UNISIG ATM interface
134 * 0 startup was successful
135 * errno startup failed - reason indicated
144 * Verify software version
146 if (atm_version != ATM_VERSION) {
147 log(LOG_ERR, "version mismatch: unisig=%d.%d kernel=%d.%d\n",
148 ATM_VERS_MAJ(ATM_VERSION),
149 ATM_VERS_MIN(ATM_VERSION),
150 ATM_VERS_MAJ(atm_version),
151 ATM_VERS_MIN(atm_version));
156 * Atleast ensure the versioning prior to creating our
159 unisig_vc_zone = uma_zcreate("unisig vcc", sizeof(struct unisig_vccb),
160 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
161 if (unisig_vc_zone == NULL)
162 panic("unisig_start: uma_zcreate failed to create vcc zone");
163 unisig_msg_zone = uma_zcreate("unisig msg", sizeof(struct unisig_msg),
164 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
165 if (unisig_msg_zone == NULL)
166 panic("unisig_start: uma_zcreate failed to create msg zone");
167 unisig_ie_zone = uma_zcreate("unisig ie", sizeof(struct ie_generic),
168 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
169 if (unisig_ie_zone == NULL)
170 panic("unisig_start: uma_zcreate failed to create ie zone");
173 * Register ourselves with system
175 err = atm_sigmgr_register(&unisig_mgr30);
179 err = atm_sigmgr_register(&unisig_mgr31);
187 * Halt UNISIG processing
189 * This should be called just prior to unloading the module from
190 * memory. All UNISIG interfaces must be deregistered before the
191 * protocol can be shutdown.
197 * 0 startup was successful
198 * errno startup failed - reason indicated
209 * Any protocol instances still registered?
211 if ((unisig_mgr30.sm_prinst != NULL) ||
212 (unisig_mgr31.sm_prinst != NULL)) {
214 /* Yes, can't stop now */
220 * De-register from system
222 (void) atm_sigmgr_deregister(&unisig_mgr30);
223 (void) atm_sigmgr_deregister(&unisig_mgr31);
226 * Free up our storage pools
228 uma_zdestroy(unisig_vc_zone);
229 uma_zdestroy(unisig_msg_zone);
230 uma_zdestroy(unisig_ie_zone);
238 * Attach a UNISIG-controlled interface
240 * Each ATM physical interface must be attached with the signalling
241 * manager for the interface's signalling protocol (via the
242 * atm_sigmgr_attach function). This function will handle the
243 * attachment for UNISIG-controlled interfaces. A new UNISIG protocol
244 * instance will be created and then we'll just sit around waiting for
245 * status or connection requests.
247 * Function must be called at splnet.
250 * smp pointer to UNISIG signalling manager control block
251 * pip pointer to ATM physical interface control block
254 * 0 attach successful
255 * errno attach failed - reason indicated
259 unisig_attach(smp, pip)
264 struct unisig *usp = NULL;
266 ATM_DEBUG2("unisig_attach: smp=%p, pip=%p\n", smp, pip);
269 * Allocate UNISIG protocol instance control block
271 usp = malloc(sizeof(struct unisig), M_DEVBUF, M_NOWAIT | M_ZERO);
277 * Set state in UNISIG protocol instance control block
279 usp->us_state = UNISIG_NULL;
280 usp->us_proto = smp->sm_proto;
283 * Set initial call reference allocation value
288 * Link instance into manager's chain
290 LINK2TAIL((struct siginst *)usp, struct siginst, smp->sm_prinst,
298 pip->pif_sigmgr = smp;
299 pip->pif_siginst = (struct siginst *) usp;
303 * Clear our ATM address. The address will be set by user
304 * command or by registration via ILMI.
306 usp->us_addr.address_format = T_ATM_ABSENT;
307 usp->us_addr.address_length = 0;
308 usp->us_subaddr.address_format = T_ATM_ABSENT;
309 usp->us_subaddr.address_length = 0;
314 usp->us_ipserv = &uniip_ipserv;
317 * Kick-start the UNISIG protocol
319 UNISIG_TIMER(usp, 0);
322 * Log the fact that we've attached
324 log(LOG_INFO, "unisig: attached to interface %s%d\n",
325 pip->pif_name, pip->pif_unit);
329 * Reset our work if attach fails
334 UNLINK((struct siginst *)usp, struct siginst,
335 smp->sm_prinst, si_next);
339 pip->pif_sigmgr = NULL;
340 pip->pif_siginst = NULL;
349 * Detach a UNISIG-controlled interface
351 * Each ATM physical interface may be detached from its signalling
352 * manager (via the atm_sigmgr_detach function). This function will
353 * handle the detachment for all UNISIG-controlled interfaces. All
354 * circuits will be immediately terminated.
356 * Function must be called at splnet.
359 * pip pointer to ATM physical interface control block
362 * 0 detach successful
363 * errno detach failed - reason indicated
373 ATM_DEBUG1("unisig_detach: pip=%p\n", pip);
376 * Get UNISIG protocol instance
378 usp = (struct unisig *)pip->pif_siginst;
381 * Return an error if we're already detaching
383 if (usp->us_state == UNISIG_DETACH) {
388 * Pass the detach event to the signalling manager
391 err = unisig_sigmgr_state(usp, UNISIG_SIGMGR_DETACH,
395 * Log the fact that we've detached
398 log(LOG_INFO, "unisig: detached from interface %s%d\n",
399 pip->pif_name, pip->pif_unit);
406 * Open a UNISIG ATM Connection
408 * All service user requests to open a VC connection (via
409 * atm_open_connection) over an ATM interface attached to the UNISIG
410 * signalling manager are handled here.
412 * Function will be called at splnet.
415 * cvp pointer to user's requested connection parameters
416 * errp pointer to an int for extended error information
419 * CALL_PROCEEDING connection establishment is in progress
420 * CALL_FAILED connection establishment failed
421 * CALL_CONNECTED connection has been successfully established
425 unisig_setup(cvp, errp)
429 struct atm_pif *pip = cvp->cvc_attr.nif->nif_pif;
430 struct unisig *usp = (struct unisig *)pip->pif_siginst;
433 ATM_DEBUG1("unisig_setup: cvp=%p\n", cvp);
436 * Intialize the returned error code
441 * Open the connection
443 switch (cvp->cvc_attr.called.addr.address_format) {
448 *errp = unisig_open_vcc(usp, cvp);
449 rc = (*errp ? CALL_FAILED : CALL_CONNECTED);
452 case T_ATM_ENDSYS_ADDR:
453 case T_ATM_E164_ADDR:
458 *errp = unisig_open_vcc(usp, cvp);
459 rc = (*errp ? CALL_FAILED : CALL_PROCEEDING);
463 *errp = EPROTONOSUPPORT;
472 * Close a UNISIG ATM Connection
474 * All service user requests to terminate a previously open VC
475 * connection (via the atm_close_connection function), which is running
476 * over an interface attached to the UNISIG signalling manager, are
479 * Function will be called at splnet.
482 * vcp pointer to connection's VC control block
483 * errp pointer to an int for extended error information
486 * CALL_PROCEEDING connection termination is in progress
487 * CALL_FAILED connection termination failed
488 * CALL_CLEARED connection has been successfully terminated
492 unisig_release(vcp, errp)
497 struct atm_pif *pip = vcp->vc_pif;
498 struct unisig *usp = (struct unisig *)pip->pif_siginst;
500 ATM_DEBUG1("unisig_release: vcp=%p\n", vcp);
503 * Initialize returned error code
508 * Validate the connection type (PVC or SVC)
510 if (!(vcp->vc_type & (VCC_PVC | VCC_SVC))) {
511 *errp = EPROTONOSUPPORT;
518 *errp = unisig_close_vcc(usp, (struct unisig_vccb *)vcp);
521 * Set the return code
525 } else if (vcp->vc_sstate == UNI_NULL ||
526 vcp->vc_sstate == UNI_FREE) {
529 rc = CALL_PROCEEDING;
537 * Accept a UNISIG Open from a remote host
539 * A user calls this routine (via the atm_accept_call function)
540 * after it is notified that an open request was received for it.
542 * Function will be called at splnet.
545 * vcp pointer to user's VCCB
546 * errp pointer to an int for extended error information
549 * CALL_PROCEEDING connection establishment is in progress
550 * CALL_FAILED connection establishment failed
551 * CALL_CONNECTED connection has been successfully established
555 unisig_accept(vcp, errp)
559 struct unisig_vccb *uvp = (struct unisig_vccb *)vcp;
560 struct atm_pif *pip = uvp->uv_pif;
561 struct unisig *usp = (struct unisig *)pip->pif_siginst;
563 ATM_DEBUG1("unisig_accept: vcp=%p\n", vcp);
566 * Initialize the returned error code
571 * Return an error if we're detaching
573 if (usp->us_state == UNISIG_DETACH) {
579 * Return an error if we lost the connection
581 if (uvp->uv_sstate == UNI_FREE) {
587 * Pass the acceptance to the VC state machine
589 *errp = unisig_vc_state(usp, uvp, UNI_VC_ACCEPT_CALL,
590 (struct unisig_msg *) 0);
594 return(CALL_PROCEEDING);
598 * On error, free the VCCB and return CALL_FAILED
602 uvp->uv_sstate = UNI_FREE;
603 uvp->uv_ustate = VCCU_CLOSED;
604 DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
605 unisig_free((struct vccb *)uvp);
612 * Reject a UNISIG Open from a remote host
614 * A user calls this routine (via the atm_reject_call function)
615 * after it is notified that an open request was received for it.
617 * Function will be called at splnet.
620 * uvp pointer to user's VCCB
621 * errp pointer to an int for extended error information
624 * CALL_CLEARED call request rejected
625 * CALL_FAILED call rejection failed
629 unisig_reject(vcp, errp)
633 struct unisig_vccb *uvp = (struct unisig_vccb *)vcp;
634 struct atm_pif *pip = uvp->uv_pif;
635 struct unisig *usp = (struct unisig *)pip->pif_siginst;
637 ATM_DEBUG1("unisig_reject: uvp=%p\n", uvp);
640 * Initialize the returned error code
646 * Return an error if we're detaching
648 if (usp->us_state == UNISIG_DETACH) {
654 * Call the VC state machine
656 *errp = unisig_vc_state(usp, uvp, UNI_VC_REJECT_CALL,
657 (struct unisig_msg *) 0);
661 return(CALL_CLEARED);
665 * On error, free the VCCB and return CALL_FAILED
667 uvp->uv_sstate = UNI_FREE;
668 uvp->uv_ustate = VCCU_CLOSED;
669 DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
670 (void) unisig_free((struct vccb *)uvp);
676 * Abort a UNISIG ATM Connection
678 * All (non-user) requests to abort a previously open VC connection (via
679 * the atm_abort_connection function), which is running over an
680 * interface attached to the UNISIG signalling manager, are handled here.
681 * The VCC owner will be notified of the request, in order to initiate
682 * termination of the connection.
684 * Function will be called at splnet.
687 * vcp pointer to connection's VC control block
690 * 0 connection release was successful
691 * errno connection release failed - reason indicated
699 ATM_DEBUG1("unisig_abort: vcp=%p\n", vcp);
704 if (vcp->vc_ustate == VCCU_ABORT) {
709 * Cancel any timer that might be running
711 UNISIG_VC_CANCEL(vcp);
714 * Set immediate timer to schedule connection termination
716 vcp->vc_ustate = VCCU_ABORT;
717 UNISIG_VC_TIMER(vcp, 0);
724 * Free UNISIG ATM connection resources
726 * All service user requests to free the resources of a closed VCC
727 * connection (via the atm_free_connection function), which is running
728 * over an interface attached to the UNISIG signalling manager, are
731 * Function will be called at splnet.
734 * vcp pointer to connection's VC control block
737 * 0 connection free was successful
738 * errno connection free failed - reason indicated
745 struct atm_pif *pip = vcp->vc_pif;
746 struct unisig *usp = (struct unisig *)pip->pif_siginst;
748 ATM_DEBUG1("unisig_free: vcp = %p\n", vcp);
751 * Make sure VCC has been closed
753 if ((vcp->vc_ustate != VCCU_CLOSED &&
754 vcp->vc_ustate != VCCU_ABORT) ||
755 vcp->vc_sstate != UNI_FREE) {
756 ATM_DEBUG2("unisig_free: bad state, sstate=%d, ustate=%d\n",
757 vcp->vc_sstate, vcp->vc_ustate);
762 * Remove VCCB from protocol queue
764 DEQUEUE(vcp, struct vccb, vc_sigelem, usp->us_vccq);
769 vcp->vc_ustate = VCCU_NULL;
770 vcp->vc_sstate = UNI_NULL;
771 uma_zfree(unisig_vc_zone, vcp);
774 * If we're detaching and this was the last VCC queued,
775 * get rid of the protocol instance
777 if ((usp->us_state == UNISIG_DETACH) &&
778 (Q_HEAD(usp->us_vccq, struct vccb) == NULL)) {
779 struct sigmgr *smp = pip->pif_sigmgr;
782 pip->pif_sigmgr = NULL;
783 pip->pif_siginst = NULL;
786 UNLINK((struct siginst *)usp, struct siginst,
787 smp->sm_prinst, si_next);
796 * UNISIG IOCTL support
798 * Function will be called at splnet.
801 * code PF_ATM sub-operation code
802 * data pointer to code specific parameter data area
803 * arg1 pointer to code specific argument
807 * errno error processing request - reason indicated
811 unisig_ioctl(code, data, arg1)
816 struct atmdelreq *adp;
817 struct atminfreq *aip;
818 struct atmsetreq *asp;
820 struct unisig_vccb *uvp;
821 struct air_vcc_rsp rsp;
829 ATM_DEBUG1("unisig_ioctl: code=%d\n", code);
838 adp = (struct atmdelreq *)data;
839 usp = (struct unisig *)arg1;
842 * Don't let a user close the UNISIG signalling VC
844 vpi = adp->adr_pvc_vpi;
845 vci = adp->adr_pvc_vci;
846 if ((vpi == UNISIG_SIG_VPI && vci == UNISIG_SIG_VCI))
852 for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
853 uvp = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem)) {
854 if ((uvp->uv_vpi == vpi) && (uvp->uv_vci == vci))
865 if (!(uvp->uv_type & VCC_PVC)) {
870 if (!(uvp->uv_type & VCC_SVC)) {
877 * Schedule VCC termination
879 unisig_cause_attr_from_user(&uvp->uv_connvc->cvc_attr,
880 T_ATM_CAUSE_UNSPECIFIED_NORMAL);
881 err = unisig_abort((struct vccb *)uvp);
886 * Return VCC information
888 aip = (struct atminfreq *)data;
889 usp = (struct unisig *)arg1;
891 buf_addr = aip->air_buf_addr;
892 buf_len = aip->air_buf_len;
895 * Loop through the VCC queue
897 for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
898 uvp = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem)) {
900 * Make sure there's room in the user's buffer
902 if (buf_len < sizeof(rsp)) {
908 * Fill out the response struct for the VCC
910 (void) snprintf(rsp.avp_intf,
911 sizeof(rsp.avp_intf), "%s%d",
912 usp->us_pif->pif_name,
913 usp->us_pif->pif_unit);
914 rsp.avp_vpi = uvp->uv_vpi;
915 rsp.avp_vci = uvp->uv_vci;
916 rsp.avp_type = uvp->uv_type;
917 rsp.avp_aal = uvp->uv_connvc->cvc_attr.aal.type;
918 rsp.avp_sig_proto = uvp->uv_proto;
919 cop = uvp->uv_connvc->cvc_conn;
921 rsp.avp_encaps = cop->co_mpx;
924 rsp.avp_state = uvp->uv_sstate;
925 if (uvp->uv_connvc->cvc_flags & CVCF_CALLER) {
926 rsp.avp_daddr = uvp->uv_connvc->cvc_attr.called.addr;
928 rsp.avp_daddr = uvp->uv_connvc->cvc_attr.calling.addr;
930 rsp.avp_dsubaddr.address_format = T_ATM_ABSENT;
931 rsp.avp_dsubaddr.address_length = 0;
932 rsp.avp_ipdus = uvp->uv_ipdus;
933 rsp.avp_opdus = uvp->uv_opdus;
934 rsp.avp_ibytes = uvp->uv_ibytes;
935 rsp.avp_obytes = uvp->uv_obytes;
936 rsp.avp_ierrors = uvp->uv_ierrors;
937 rsp.avp_oerrors = uvp->uv_oerrors;
938 rsp.avp_tstamp = uvp->uv_tstamp;
939 bzero(rsp.avp_owners,
940 sizeof(rsp.avp_owners));
941 for (i = 0; cop && i < sizeof(rsp.avp_owners);
943 i += T_ATM_APP_NAME_LEN+1) {
944 strncpy(&rsp.avp_owners[i],
945 cop->co_endpt->ep_getname(cop->co_toku),
950 * Copy the response into the user's buffer
952 if ((err = copyout((caddr_t)&rsp, buf_addr,
955 buf_addr += sizeof(rsp);
956 buf_len -= sizeof(rsp);
960 * Update the buffer pointer and length
962 aip->air_buf_addr = buf_addr;
963 aip->air_buf_len = buf_len;
970 * Get ARP table information or get/set ARP server address
972 err = uniarp_ioctl(code, data, arg1);
979 asp = (struct atmsetreq *)data;
980 usp = (struct unisig *)arg1;
982 if (usp->us_addr.address_format != T_ATM_ABSENT) {
983 if (bcmp(asp->asr_prf_pref, usp->us_addr.address,
984 sizeof(asp->asr_prf_pref)) != 0)
988 usp->us_addr.address_format = T_ATM_ENDSYS_ADDR;
989 usp->us_addr.address_length = sizeof(Atm_addr_nsap);
990 bcopy(&pip->pif_macaddr,
991 ((Atm_addr_nsap *)usp->us_addr.address)->aan_esi,
992 sizeof(pip->pif_macaddr));
993 bcopy((caddr_t) asp->asr_prf_pref,
994 &((Atm_addr_nsap *)usp->us_addr.address)->aan_afi,
995 sizeof(asp->asr_prf_pref));
996 log(LOG_INFO, "uni: set address %s on interface %s\n",
997 unisig_addr_print(&usp->us_addr),
1001 * Pass event to signalling manager state machine
1003 err = unisig_sigmgr_state(usp, UNISIG_SIGMGR_ADDR_SET,
1007 * Clean up if there was an error
1010 usp->us_addr.address_format = T_ATM_ABSENT;
1011 usp->us_addr.address_length = 0;
1016 * Inform ARP code of new address
1018 uniarp_ifaddr((struct siginst *)usp);