45823932f8ad92ca9ba20c5f78b7274102e1ea76
[dragonfly.git] / sys / netproto / atm / uni / unisig_subr.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/netatm/uni/unisig_subr.c,v 1.7 2000/01/17 20:49:58 mks Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/uni/unisig_subr.c,v 1.6 2006/01/14 13:36:39 swildner Exp $
28  */
29
30 /*
31  * ATM Forum UNI 3.0/3.1 Signalling Manager
32  * ----------------------------------------
33  *
34  * Subroutines
35  *
36  */
37
38 #include <netproto/atm/kern_include.h>
39
40 #include "unisig_var.h"
41 #include "unisig_msg.h"
42
43 /*
44  * External variables
45  */
46 extern struct ie_aalp  ie_aalp_absent;
47 extern struct ie_clrt  ie_clrt_absent;
48 extern struct ie_bbcp  ie_bbcp_absent;
49 extern struct ie_bhli  ie_bhli_absent;
50 extern struct ie_blli  ie_blli_absent;
51 extern struct ie_clst  ie_clst_absent;
52 extern struct ie_cdad  ie_cdad_absent;
53 extern struct ie_cdsa  ie_cdsa_absent;
54 extern struct ie_cgad  ie_cgad_absent;
55 extern struct ie_cgsa  ie_cgsa_absent;
56 extern struct ie_caus  ie_caus_absent;
57 extern struct ie_cnid  ie_cnid_absent;
58 extern struct ie_qosp  ie_qosp_absent;
59 extern struct ie_brpi  ie_brpi_absent;
60 extern struct ie_rsti  ie_rsti_absent;
61 extern struct ie_blsh  ie_blsh_absent;
62 extern struct ie_bnsh  ie_bnsh_absent;
63 extern struct ie_bsdc  ie_bsdc_absent;
64 extern struct ie_trnt  ie_trnt_absent;
65 extern struct ie_eprf  ie_eprf_absent;
66 extern struct ie_epst  ie_epst_absent;
67
68
69 /*
70  * Set a User Location cause code in an ATM attribute block
71  *
72  * Arguments:
73  *      aap     pointer to attribute block
74  *      cause   cause code
75  *
76  * Returns:
77  *      none
78  *
79  */
80 void
81 unisig_cause_attr_from_user(Atm_attributes *aap, int cause)
82 {
83         if (cause == T_ATM_ABSENT)
84                 return;
85
86         /*
87          * Set the fields in the attribute block
88          */
89         aap->cause.tag = T_ATM_PRESENT;
90         aap->cause.v.coding_standard = T_ATM_ITU_CODING;
91         aap->cause.v.location = T_ATM_LOC_USER;
92         aap->cause.v.cause_value = cause;
93         KM_ZERO(aap->cause.v.diagnostics,
94                         sizeof(aap->cause.v.diagnostics));
95 }
96
97
98 /*
99  * Set a cause code in an ATM attribute block from a Cause IE
100  *
101  * Arguments:
102  *      aap     pointer to attribute block
103  *      iep     pointer to Cause IE
104  *
105  * Returns:
106  *      none
107  *
108  */
109 void
110 unisig_cause_attr_from_ie(Atm_attributes *aap, struct ie_generic *iep)
111 {
112         /*
113          * Set the fields in the attribute block
114          */
115         aap->cause.tag = T_ATM_PRESENT;
116         aap->cause.v.coding_standard = iep->ie_coding;
117         aap->cause.v.location = iep->ie_caus_loc;
118         aap->cause.v.cause_value = iep->ie_caus_cause;
119         KM_ZERO(aap->cause.v.diagnostics, sizeof(aap->cause.v.diagnostics));
120         KM_COPY(iep->ie_caus_diagnostic, aap->cause.v.diagnostics,
121                 MIN(sizeof(aap->cause.v.diagnostics), iep->ie_caus_diag_len));
122 }
123
124
125 /*
126  * Open a UNI VCC
127  *
128  * Called when a user wants to open a VC.  This function will construct
129  * a VCCB and, if we are opening an SVC, call the Q.2931 VC state
130  * machine.  The user will have to wait for a notify event to be sure
131  * the SVC is fully open.
132  *
133  * Must be called from a critical section.
134  *
135  * Arguments:
136  *      usp     pointer to UNISIG protocol instance
137  *      cvp     pointer to connection parameters for the VCC
138  *
139  * Returns:
140  *      0       VCC creation successful
141  *      errno   VCC setup failed - reason indicated
142  *
143  */
144 int
145 unisig_open_vcc(struct unisig *usp, Atm_connvc *cvp)
146 {
147         struct atm_pif          *pip = usp->us_pif;
148         struct unisig_vccb      *uvp;
149         Atm_addr_pvc            *pvp;
150         int                     err, pvc;
151
152         ATM_DEBUG2("unisig_open_vcc: usp=%p, cvp=%p\n", usp, cvp);
153
154         /*
155          * Validate user parameters.  AAL and encapsulation are
156          * checked by the connection manager
157          */
158
159         /*
160          * Check called party address(es)
161          */
162         if(cvp->cvc_attr.called.tag != T_ATM_PRESENT ||
163                         cvp->cvc_attr.called.addr.address_format ==
164                                 T_ATM_ABSENT) {
165                 return(EINVAL);
166         }
167         switch (cvp->cvc_attr.called.addr.address_format) {
168         case T_ATM_PVC_ADDR:
169                 /*
170                  * Make sure VPI/VCI is valid
171                  */
172                 pvc = 1;
173                 pvp = (Atm_addr_pvc *)cvp->cvc_attr.called.addr.address;
174                 if ((ATM_PVC_GET_VPI(pvp) > pip->pif_maxvpi) ||
175                                 (ATM_PVC_GET_VCI(pvp) == 0) ||
176                                 (ATM_PVC_GET_VCI(pvp) > pip->pif_maxvci)) {
177                         return(ERANGE);
178                 }
179
180                 /*
181                  * Make sure VPI/VCI is not already in use
182                  */
183                 if (unisig_find_vpvc(usp,
184                                 ATM_PVC_GET_VPI(pvp),
185                                 ATM_PVC_GET_VCI(pvp), 0)) {
186                         return(EEXIST);
187                 }
188                 ATM_DEBUG2("unisig_open_vcc: VPI.VCI=%d.%d\n",
189                                 ATM_PVC_GET_VPI(pvp),
190                                 ATM_PVC_GET_VCI(pvp));
191                 break;
192
193         case T_ATM_ENDSYS_ADDR:
194                 /*
195                  * Check signalling state
196                  */
197                 pvc = 0;
198                 pvp = NULL;
199                 if (usp->us_state != UNISIG_ACTIVE) {
200                         return(ENETDOWN);
201                 }
202
203                 /*
204                  * Make sure there's no subaddress
205                  */
206                 if (cvp->cvc_attr.called.subaddr.address_format !=
207                                 T_ATM_ABSENT) {
208                         return(EINVAL);
209                 }
210                 break;
211
212         case T_ATM_E164_ADDR:
213                 /*
214                  * Check signalling state
215                  */
216                 pvc = 0;
217                 pvp = NULL;
218                 if (usp->us_state != UNISIG_ACTIVE) {
219                         return(ENETDOWN);
220                 }
221
222                 /*
223                  * Check destination address format
224                  */
225                 if (cvp->cvc_attr.called.subaddr.address_format !=
226                                         T_ATM_ENDSYS_ADDR &&
227                                 cvp->cvc_attr.called.subaddr.address_format !=
228                                         T_ATM_ABSENT) {
229                         return(EINVAL);
230                 }
231                 break;
232
233         default:
234                 return(EPROTONOSUPPORT);
235         }
236
237         /*
238          * Check that this is for the same interface UNISIG uses
239          */
240         if (!cvp->cvc_attr.nif ||
241                         cvp->cvc_attr.nif->nif_pif != usp->us_pif) {
242                 return(EINVAL);
243         }
244
245         /*
246          * Allocate control block for VCC
247          */
248         uvp = (struct unisig_vccb *)atm_allocate(&unisig_vcpool);
249         if (uvp == NULL) {
250                 return(ENOMEM);
251         }
252
253         /*
254          * Fill in VCCB
255          */
256         if (pvc) {
257                 uvp->uv_type = VCC_PVC | VCC_IN | VCC_OUT;
258                 uvp->uv_vpi = ATM_PVC_GET_VPI(pvp);
259                 uvp->uv_vci = ATM_PVC_GET_VCI(pvp);
260                 uvp->uv_sstate = (usp->us_state == UNISIG_ACTIVE ?
261                                 UNI_PVC_ACTIVE : UNI_PVC_ACT_DOWN);
262                 uvp->uv_ustate = VCCU_OPEN;
263         } else {
264                 uvp->uv_type = VCC_SVC | VCC_IN | VCC_OUT;
265                 uvp->uv_sstate = UNI_NULL;
266                 uvp->uv_ustate = VCCU_POPEN;
267         }
268         uvp->uv_proto = usp->us_pif->pif_sigmgr->sm_proto;
269         uvp->uv_pif = usp->us_pif;
270         uvp->uv_nif = cvp->cvc_attr.nif;
271         uvp->uv_connvc = cvp;
272         uvp->uv_tstamp = time_second;
273
274         /*
275          * Put VCCB on UNISIG queue
276          */
277         ENQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
278
279         /*
280          * Call the VC state machine if this is an SVC
281          */
282         if (!pvc) {
283                 err = unisig_vc_state(usp, uvp, UNI_VC_SETUP_CALL,
284                                 (struct unisig_msg *) 0);
285                 if (err) {
286                         /*
287                          * On error, delete the VCCB
288                          */
289                         DEQUEUE(uvp, struct unisig_vccb, uv_sigelem,
290                                         usp->us_vccq);
291                         atm_free((caddr_t)uvp);
292                         return(err);
293                 }
294         }
295
296         /*
297          * Link VCCB to VCC connection block
298          */
299         cvp->cvc_vcc = (struct vccb *) uvp;
300
301         return(0);
302 }
303
304
305 /*
306  * Close a UNISIG VCC
307  *
308  * Called when a user wants to close a VCC.  This function will clean
309  * up the VCCB and, for an SVC, send a close request.
310  *
311  * Must be called from a critical section.
312  *
313  * Arguments:
314  *      usp     pointer to UNISIG protocol instance
315  *      uvp     pointer to VCCB for the VCC to be closed
316  *
317  * Returns:
318  *      0       VCC is now closed
319  *      errno   error encountered
320  */
321 int
322 unisig_close_vcc(struct unisig *usp, struct unisig_vccb *uvp)
323 {
324         int             err = 0;
325
326         ATM_DEBUG2("unisig_close_vcc: uvp=%p, state=%d\n", uvp,
327                         uvp->uv_sstate);
328
329         /*
330          * Check that this is for the same interface UNISIG uses
331          */
332         if (uvp->uv_pif != usp->us_pif) {
333                 return (EINVAL);
334         }
335
336         /*
337          * Mark the close time.
338          */
339         uvp->uv_tstamp = time_second;
340
341         /*
342          * Process based on the connection type
343          */
344         if (uvp->uv_type & VCC_PVC) {
345                 uvp->uv_sstate = UNI_FREE;
346                 uvp->uv_ustate = VCCU_CLOSED;
347         } else if (uvp->uv_type & VCC_SVC) {
348                 /*
349                  * Call the VC state machine
350                  */
351                 uvp->uv_ustate = VCCU_CLOSED;
352                 err = unisig_vc_state(usp, uvp, UNI_VC_RELEASE_CALL,
353                                 (struct unisig_msg *) 0);
354         }
355
356         /*
357          * Wait for user to free resources
358          */
359         return(err);
360 }
361
362
363 /*
364  * Clear a UNISIG VCC
365  *
366  * Called to internally clear a VCC.  No external protocol is
367  * initiated, the VCC is just closed and the owner is notified.
368  *
369  * Must be called from a critical section.
370  *
371  * Arguments:
372  *      usp     pointer to UNISIG protocol instance
373  *      uvp     pointer to VCCB for the VCC to be closed
374  *      cause   cause code giving the reason for the close
375  *
376  * Returns:
377  *      0       VCC is closed
378  *      errno   error encountered
379  */
380 int
381 unisig_clear_vcc(struct unisig *usp, struct unisig_vccb *uvp, int cause)
382 {
383         u_char  outstate;
384
385         ATM_DEBUG3("unisig_clear_vcc: uvp=%p, state=%d, cause=%d\n",
386                         uvp, uvp->uv_sstate, cause);
387
388         /*
389          * Check that this is for the same interface UNISIG uses
390          */
391         if (uvp->uv_pif != usp->us_pif) {
392                 return (EINVAL);
393         }
394
395         /*
396          * Kill any possible timer
397          */
398         UNISIG_VC_CANCEL((struct vccb *) uvp);
399
400         /*
401          * Mark the close time.
402          */
403         uvp->uv_tstamp = time_second;
404
405         /*
406          * Close the VCC and notify the user
407          */
408         outstate = uvp->uv_sstate;
409         uvp->uv_sstate = UNI_FREE;
410         uvp->uv_ustate = VCCU_CLOSED;
411         if (outstate == UNI_ACTIVE ||
412                         outstate == UNI_CALL_INITIATED ||
413                         outstate == UNI_CALL_OUT_PROC ||
414                         outstate == UNI_CONNECT_REQUEST ||
415                         outstate == UNI_RELEASE_REQUEST ||
416                         outstate == UNI_RELEASE_IND ||
417                         outstate == UNI_SSCF_RECOV ||
418                         outstate == UNI_PVC_ACT_DOWN ||
419                         outstate == UNI_PVC_ACTIVE) {
420                 unisig_cause_attr_from_user(&uvp->uv_connvc->cvc_attr, cause);
421                 atm_cm_cleared(uvp->uv_connvc);
422         }
423
424         /*
425          * Wait for user to free resources
426          */
427         return(0);
428 }
429
430
431 #ifdef NOTDEF
432 /*
433  * Reset the switch state
434  *
435  * Arguments:
436  *      usp     pointer to UNISIG protocol instance
437  *
438  * Returns:
439  *      none
440  *
441  */
442 void
443 unisig_switch_reset(struct unisig *usp, int cause)
444 {
445         struct unisig_vccb      *uvp, *vnext;
446
447         ATM_DEBUG2("unisig_switch_reset: usp=%p, cause=%d\n",
448                         usp, cause);
449
450         /*
451          * Terminate all of our VCCs
452          */
453         crit_enter();
454         for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
455                         uvp = vnext) {
456                 vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem);
457
458                 if (uvp->uv_type & VCC_SVC) {
459                         /*
460                          * Close the SVC and notify the owner
461                          */
462                         unisig_clear_vcc(usp, uvp,
463                                         T_ATM_CAUSE_NORMAL_CALL_CLEARING);
464                 } else if (uvp->uv_type & VCC_PVC) {
465                         /*
466                          * Notify PVC owner of the state change
467                          */
468                         switch(cause) {
469                         case UNI_DOWN:
470                                 uvp->uv_sstate = UNI_PVC_ACT_DOWN;
471                                 break;
472                         case UNI_UP:
473                                 uvp->uv_sstate = UNI_PVC_ACTIVE;
474                                 break;
475                         }
476                         atm_cm_cleared(uvp->uv_connvc, cause);
477                 } else {
478                         log(LOG_ERR, "unisig: invalid VCC type: vccb=%p, type=%d\n",
479                                         uvp, uvp->uv_type);
480                 }
481         }
482         crit_exit();
483 }
484 #endif
485
486
487 /*
488  * Copy connection parameters from UNI 3.0 message IEs into
489  * an attribute block
490  *
491  * Arguments:
492  *      usp     pointer to UNISIG protocol instance
493  *      msg     pointer to the SETUP message
494  *      ap      pointer to the attribute block
495  *
496  * Returns:
497  *      none
498  *
499  */
500 void
501 unisig_save_attrs(struct unisig *usp, struct unisig_msg *msg,
502                   Atm_attributes *ap)
503 {
504         /*
505          * Sanity check
506          */
507         if (!msg || !ap)
508                 return;
509
510         /*
511          * Save the AAL parameters (AAL 3/4 and AAL 5 only)
512          */
513         if (msg->msg_ie_aalp) {
514                 struct ie_generic       *aalp = msg->msg_ie_aalp;
515
516                 switch(msg->msg_ie_aalp->ie_aalp_aal_type) {
517                 case UNI_IE_AALP_AT_AAL3:
518                         ap->aal.tag = T_ATM_PRESENT;
519                         ap->aal.type =
520                                 msg->msg_ie_aalp->ie_aalp_aal_type;
521                         ap->aal.v.aal4.forward_max_SDU_size =
522                                 msg->msg_ie_aalp->ie_aalp_4_fwd_max_sdu;
523                         ap->aal.v.aal4.backward_max_SDU_size =
524                                 msg->msg_ie_aalp->ie_aalp_4_bkwd_max_sdu;
525                         ap->aal.v.aal4.SSCS_type =
526                                 msg->msg_ie_aalp->ie_aalp_4_sscs_type;
527                         if (aalp->ie_aalp_4_mid_range == T_ATM_ABSENT) {
528                                 ap->aal.v.aal4.mid_low = T_ATM_ABSENT;
529                                 ap->aal.v.aal4.mid_high = T_ATM_ABSENT;
530                         } else {
531                                 if (usp->us_proto == ATM_SIG_UNI30) {
532                                         ap->aal.v.aal4.mid_low = 0;
533                                         ap->aal.v.aal4.mid_high =
534                                                 aalp->ie_aalp_4_mid_range
535                                                         & UNI_IE_AALP_A3_R_MASK;
536                                 } else {
537                                         ap->aal.v.aal4.mid_low =
538                                                 (aalp->ie_aalp_4_mid_range >>
539                                                         UNI_IE_AALP_A3_R_SHIFT)
540                                                         & UNI_IE_AALP_A3_R_MASK;
541                                         ap->aal.v.aal4.mid_high =
542                                                 aalp->ie_aalp_4_mid_range
543                                                         & UNI_IE_AALP_A3_R_MASK;
544                                 }
545                         }
546                         break;
547                 case UNI_IE_AALP_AT_AAL5:
548                         ap->aal.tag = T_ATM_PRESENT;
549                         ap->aal.type =
550                                 msg->msg_ie_aalp->ie_aalp_aal_type;
551                         ap->aal.v.aal5.forward_max_SDU_size =
552                                 msg->msg_ie_aalp->ie_aalp_5_fwd_max_sdu;
553                         ap->aal.v.aal5.backward_max_SDU_size =
554                                 msg->msg_ie_aalp->ie_aalp_5_bkwd_max_sdu;
555                         ap->aal.v.aal5.SSCS_type =
556                                 msg->msg_ie_aalp->ie_aalp_5_sscs_type;
557                         break;
558                 }
559         }
560
561         /*
562          * Save traffic descriptor attributes
563          */
564         if (msg->msg_ie_clrt) {
565                 ap->traffic.tag = T_ATM_PRESENT;
566                 ap->traffic.v.forward.PCR_high_priority =
567                                 msg->msg_ie_clrt->ie_clrt_fwd_peak;
568                 ap->traffic.v.forward.PCR_all_traffic =
569                                 msg->msg_ie_clrt->ie_clrt_fwd_peak_01;
570                 ap->traffic.v.forward.SCR_high_priority =
571                                 msg->msg_ie_clrt->ie_clrt_fwd_sust;
572                 ap->traffic.v.forward.SCR_all_traffic =
573                                 msg->msg_ie_clrt->ie_clrt_fwd_sust_01;
574                 ap->traffic.v.forward.MBS_high_priority =
575                                 msg->msg_ie_clrt->ie_clrt_fwd_burst;
576                 ap->traffic.v.forward.MBS_all_traffic =
577                                 msg->msg_ie_clrt->ie_clrt_fwd_burst_01;
578                 ap->traffic.v.backward.PCR_high_priority =
579                                 msg->msg_ie_clrt->ie_clrt_bkwd_peak;
580                 ap->traffic.v.backward.PCR_all_traffic =
581                                 msg->msg_ie_clrt->ie_clrt_bkwd_peak_01;
582                 ap->traffic.v.backward.SCR_high_priority =
583                                 msg->msg_ie_clrt->ie_clrt_bkwd_sust;
584                 ap->traffic.v.backward.SCR_all_traffic =
585                                 msg->msg_ie_clrt->ie_clrt_bkwd_sust_01;
586                 ap->traffic.v.backward.MBS_high_priority =
587                                 msg->msg_ie_clrt->ie_clrt_bkwd_burst;
588                 ap->traffic.v.backward.MBS_all_traffic =
589                                 msg->msg_ie_clrt->ie_clrt_bkwd_burst_01;
590                 ap->traffic.v.best_effort =
591                                 msg->msg_ie_clrt->ie_clrt_best_effort;
592                 if (msg->msg_ie_clrt->ie_clrt_tm_options ==
593                                 T_ATM_ABSENT) {
594                         ap->traffic.v.forward.tagging = T_NO;
595                         ap->traffic.v.backward.tagging = T_NO;
596                 } else {
597                         ap->traffic.v.forward.tagging =
598                                         (msg->msg_ie_clrt->ie_clrt_tm_options &
599                                         UNI_IE_CLRT_TM_FWD_TAG) != 0;
600                         ap->traffic.v.backward.tagging =
601                                         (msg->msg_ie_clrt->ie_clrt_tm_options &
602                                         UNI_IE_CLRT_TM_BKWD_TAG) != 0;
603                 }
604         }
605
606         /*
607          * Save broadband bearer attributes
608          */
609         if (msg->msg_ie_bbcp) {
610                 ap->bearer.tag = T_ATM_PRESENT;
611                 ap->bearer.v.bearer_class =
612                                 msg->msg_ie_bbcp->ie_bbcp_bearer_class;
613                 ap->bearer.v.traffic_type =
614                                 msg->msg_ie_bbcp->ie_bbcp_traffic_type;
615                 ap->bearer.v.timing_requirements =
616                                 msg->msg_ie_bbcp->ie_bbcp_timing_req;
617                 ap->bearer.v.clipping_susceptibility =
618                                 msg->msg_ie_bbcp->ie_bbcp_clipping;
619                 ap->bearer.v.connection_configuration =
620                                 msg->msg_ie_bbcp->ie_bbcp_conn_config;
621         }
622
623         /*
624          * Save broadband high layer attributes
625          */
626         if (msg->msg_ie_bhli) {
627                 ap->bhli.tag = T_ATM_PRESENT;
628                 ap->bhli.v.ID_type = msg->msg_ie_bhli->ie_bhli_type;
629                 switch(ap->bhli.v.ID_type) {
630                 case T_ATM_ISO_APP_ID:
631                         KM_COPY(msg->msg_ie_bhli->ie_bhli_info,
632                                         ap->bhli.v.ID.ISO_ID,
633                                         sizeof(ap->bhli.v.ID.ISO_ID));
634                         break;
635                 case T_ATM_USER_APP_ID:
636                         KM_COPY(msg->msg_ie_bhli->ie_bhli_info,
637                                         ap->bhli.v.ID.user_defined_ID,
638                                         sizeof(ap->bhli.v.ID.user_defined_ID));
639                         break;
640                 case T_ATM_VENDOR_APP_ID:
641                         KM_COPY(msg->msg_ie_bhli->ie_bhli_info,
642                                         ap->bhli.v.ID.vendor_ID.OUI,
643                                         sizeof(ap->bhli.v.ID.vendor_ID.OUI));
644                         KM_COPY(&msg->msg_ie_bhli->ie_bhli_info[sizeof(ap->bhli.v.ID.vendor_ID.OUI)-1],
645                                         ap->bhli.v.ID.vendor_ID.app_ID,
646                                         sizeof(ap->bhli.v.ID.vendor_ID.app_ID));
647                         break;
648                 }
649         }
650
651         /*
652          * Save Broadband low layer, user layer 2 and 3 attributes
653          */
654         if (msg->msg_ie_blli) {
655                 /*
656                  * Layer 2 parameters
657                  */
658                 switch(msg->msg_ie_blli->ie_blli_l2_id) {
659                 case UNI_IE_BLLI_L2P_ISO1745:
660                 case UNI_IE_BLLI_L2P_Q921:
661                 case UNI_IE_BLLI_L2P_X25L:
662                 case UNI_IE_BLLI_L2P_X25M:
663                 case UNI_IE_BLLI_L2P_LAPB:
664                 case UNI_IE_BLLI_L2P_HDLC1:
665                 case UNI_IE_BLLI_L2P_HDLC2:
666                 case UNI_IE_BLLI_L2P_HDLC3:
667                 case UNI_IE_BLLI_L2P_LLC:
668                 case UNI_IE_BLLI_L2P_X75:
669                 case UNI_IE_BLLI_L2P_Q922:
670                 case UNI_IE_BLLI_L2P_ISO7776:
671                         ap->blli.tag_l2 = T_ATM_PRESENT;
672                         ap->blli.v.layer_2_protocol.ID_type =
673                                         T_ATM_SIMPLE_ID;
674                         ap->blli.v.layer_2_protocol.ID.simple_ID =
675                                         msg->msg_ie_blli->ie_blli_l2_id;
676                         break;
677                 case UNI_IE_BLLI_L2P_USER:
678                         ap->blli.tag_l2 = T_ATM_PRESENT;
679                         ap->blli.v.layer_2_protocol.ID_type =
680                                         T_ATM_USER_ID;
681                         ap->blli.v.layer_2_protocol.ID.user_defined_ID =
682                                         msg->msg_ie_blli->ie_blli_l2_user_proto;
683                         break;
684                 default:
685                         ap->blli.tag_l2 = T_ATM_ABSENT;
686                 }
687                 if (ap->blli.tag_l2 == T_ATM_PRESENT) {
688                         ap->blli.v.layer_2_protocol.mode =
689                                         msg->msg_ie_blli->ie_blli_l2_mode;
690                         ap->blli.v.layer_2_protocol.window_size =
691                                         msg->msg_ie_blli->ie_blli_l2_window;
692                 }
693
694                 /*
695                  * Layer 3 parameters
696                  */
697                 switch(msg->msg_ie_blli->ie_blli_l3_id) {
698                 case UNI_IE_BLLI_L3P_X25:
699                 case UNI_IE_BLLI_L3P_ISO8208:
700                 case UNI_IE_BLLI_L3P_ISO8878:
701                 case UNI_IE_BLLI_L3P_ISO8473:
702                 case UNI_IE_BLLI_L3P_T70:
703                         ap->blli.tag_l3 = T_ATM_PRESENT;
704                         ap->blli.v.layer_3_protocol.ID_type =
705                                         T_ATM_SIMPLE_ID;
706                         ap->blli.v.layer_3_protocol.ID.simple_ID =
707                                         msg->msg_ie_blli->ie_blli_l3_id;
708                         break;
709                 case UNI_IE_BLLI_L3P_ISO9577:
710                         ap->blli.tag_l3 = T_ATM_PRESENT;
711                         ap->blli.v.layer_3_protocol.ID_type =
712                                         T_ATM_SIMPLE_ID;
713                         ap->blli.v.layer_3_protocol.ID.simple_ID =
714                                         msg->msg_ie_blli->ie_blli_l3_id;
715                         if (msg->msg_ie_blli->ie_blli_l3_ipi ==
716                                         UNI_IE_BLLI_L3IPI_SNAP) {
717                                 KM_COPY(msg->msg_ie_blli->ie_blli_l3_oui,
718                                                 ap->blli.v.layer_3_protocol.ID.SNAP_ID.OUI,
719                                                 sizeof(ap->blli.v.layer_3_protocol.ID.SNAP_ID.OUI));
720                                 KM_COPY(msg->msg_ie_blli->ie_blli_l3_pid,
721                                                 ap->blli.v.layer_3_protocol.ID.SNAP_ID.PID,
722                                                 sizeof(ap->blli.v.layer_3_protocol.ID.SNAP_ID.PID));
723                         } else {
724                                 ap->blli.v.layer_3_protocol.ID.IPI_ID =
725                                                 msg->msg_ie_blli->ie_blli_l3_ipi;
726                         }
727                         break;
728                 case UNI_IE_BLLI_L3P_USER:
729                         ap->blli.tag_l3 = T_ATM_PRESENT;
730                         ap->blli.v.layer_3_protocol.ID_type =
731                                         T_ATM_USER_ID;
732                         ap->blli.v.layer_3_protocol.ID.user_defined_ID =
733                                         msg->msg_ie_blli->ie_blli_l3_user_proto;
734                         break;
735                 default:
736                         ap->blli.tag_l3 = T_ATM_ABSENT;
737                 }
738                 if (ap->blli.tag_l3 == T_ATM_PRESENT) {
739                         ap->blli.v.layer_3_protocol.mode =
740                                         msg->msg_ie_blli->ie_blli_l3_mode;
741                         ap->blli.v.layer_3_protocol.packet_size =
742                                         msg->msg_ie_blli->ie_blli_l3_packet_size;
743                         ap->blli.v.layer_3_protocol.window_size =
744                                         msg->msg_ie_blli->ie_blli_l3_window;
745                 }
746         }
747
748         /*
749          * Save the called party address and subaddress
750          */
751         if (msg->msg_ie_cdad) {
752                 ap->called.tag = T_ATM_PRESENT;
753                 ATM_ADDR_COPY(&msg->msg_ie_cdad->ie_cdad_addr,
754                                 &ap->called.addr);
755                 ap->called.subaddr.address_format = T_ATM_ABSENT;
756                 ap->called.subaddr.address_length = 0;
757         }
758         if (msg->msg_ie_cdsa) {
759                 ATM_ADDR_COPY(&msg->msg_ie_cdsa->ie_cdsa_addr,
760                                 &ap->called.subaddr);
761         }
762
763         /*
764          * Save the calling party address and subaddress
765          */
766         if (msg->msg_ie_cgad) {
767                 ap->calling.tag = T_ATM_PRESENT;
768                 ATM_ADDR_COPY(&msg->msg_ie_cgad->ie_cgad_addr,
769                                 &ap->calling.addr);
770                 ap->calling.subaddr.address_format = T_ATM_ABSENT;
771                 ap->calling.subaddr.address_length = 0;
772         }
773
774         if (msg->msg_ie_cgsa) {
775                 ATM_ADDR_COPY(&msg->msg_ie_cgsa->ie_cgsa_addr,
776                                 &ap->calling.subaddr);
777         }
778
779         /*
780          * Save quality of service attributes
781          */
782         if (msg->msg_ie_qosp) {
783                 ap->qos.tag = T_ATM_PRESENT;
784                 ap->qos.v.coding_standard = msg->msg_ie_qosp->ie_coding;
785                 ap->qos.v.forward.qos_class = msg->msg_ie_qosp->ie_qosp_fwd_class;
786                 ap->qos.v.forward.qos_class =
787                                 msg->msg_ie_qosp->ie_qosp_bkwd_class;
788         }
789
790         /*
791          * Save transit network attributes
792          */
793         if (msg->msg_ie_trnt) {
794                 ap->transit.tag = T_ATM_PRESENT;
795                 ap->transit.v.length = 
796                                 MIN(msg->msg_ie_trnt->ie_trnt_id_len,
797                                 sizeof(ap->transit.v.network_id));
798                 KM_COPY(msg->msg_ie_trnt->ie_trnt_id,
799                                 ap->transit.v.network_id,
800                                 ap->transit.v.length);
801         }
802
803         /*
804          * Save cause code
805          */
806         if (msg->msg_ie_caus) {
807                 ap->cause.tag = T_ATM_PRESENT;
808                 ap->cause.v.coding_standard =
809                                 msg->msg_ie_caus->ie_coding;
810                 ap->cause.v.location = 
811                                 msg->msg_ie_caus->ie_caus_loc;
812                 ap->cause.v.cause_value = 
813                                 msg->msg_ie_caus->ie_caus_cause;
814                 KM_ZERO(ap->cause.v.diagnostics,
815                                 sizeof(ap->cause.v.diagnostics));
816 #ifdef NOTDEF
817                 KM_COPY(msg->msg_ie_caus->ie_caus_diagnostic,
818                                 ap->transit.v.diagnostics,
819                                 MIN(sizeof(ap->transit.v.diagnostics),
820                                 msg->msg_ie_caus->ie_caus_diag_len));
821 #endif
822         }
823 }
824
825
826 /*
827  * Copy connection parameters from an attribute block into
828  * UNI 3.0 message IEs
829  *
830  * Arguments:
831  *      usp     pointer to UNISIG protocol instance
832  *      msg     pointer to the SETUP message
833  *      ap      pointer to the attribute block
834  *
835  * Returns:
836  *      0       everything OK
837  *      else    error encountered
838  *
839  */
840 int
841 unisig_set_attrs(struct unisig *usp, struct unisig_msg *msg,
842                  Atm_attributes *ap)
843 {
844         int                     err = 0;
845
846         /*
847          * Sanity check
848          */
849         if (!msg || !ap)
850                 return(EINVAL);
851
852         /*
853          * Set the AAL parameters (AAL 3/4 and AAL 5 only)
854          */
855         if (ap->aal.tag == T_ATM_PRESENT) {
856                 if (!msg->msg_ie_aalp) {
857                         msg->msg_ie_aalp = (struct ie_generic *)
858                                         atm_allocate(&unisig_iepool);
859                         if (msg->msg_ie_aalp == NULL) {
860                                 err = ENOMEM;
861                                 goto done;
862                         }
863                 }
864                 KM_COPY(&ie_aalp_absent,
865                                 &msg->msg_ie_aalp->ie_u.ie_aalp,
866                                 sizeof(ie_aalp_absent));
867                 msg->msg_ie_aalp->ie_ident = UNI_IE_AALP;
868                 msg->msg_ie_aalp->ie_aalp_aal_type = ap->aal.type;
869                 switch(ap->aal.type) {
870                 case ATM_AAL3_4:
871                         msg->msg_ie_aalp->ie_aalp_4_fwd_max_sdu =
872                                         ap->aal.v.aal4.forward_max_SDU_size;
873                         msg->msg_ie_aalp->ie_aalp_4_bkwd_max_sdu =
874                                         ap->aal.v.aal4.backward_max_SDU_size;
875                         msg->msg_ie_aalp->ie_aalp_4_mode = UNI_IE_AALP_A5_M_MSG;
876                         msg->msg_ie_aalp->ie_aalp_4_sscs_type =
877                                         ap->aal.v.aal4.SSCS_type;
878                         if (ap->aal.v.aal4.mid_low == T_ATM_ABSENT) {
879                                 msg->msg_ie_aalp->ie_aalp_4_mid_range =
880                                         T_ATM_ABSENT;
881                         } else {
882                                 if (usp->us_proto == ATM_SIG_UNI30) {
883                                         msg->msg_ie_aalp->ie_aalp_4_mid_range =
884                                                 ap->aal.v.aal4.mid_high &
885                                                         UNI_IE_AALP_A3_R_MASK;
886                                 } else {
887                                         msg->msg_ie_aalp->ie_aalp_4_mid_range =
888                                                 ((ap->aal.v.aal4.mid_low &
889                                                         UNI_IE_AALP_A3_R_MASK)
890                                                     << UNI_IE_AALP_A3_R_SHIFT)
891                                                   |
892                                                  (ap->aal.v.aal4.mid_high &
893                                                         UNI_IE_AALP_A3_R_MASK);
894                                 }
895                         }
896                         break;
897                 case ATM_AAL5:
898                         msg->msg_ie_aalp->ie_aalp_5_fwd_max_sdu =
899                                         ap->aal.v.aal5.forward_max_SDU_size;
900                         msg->msg_ie_aalp->ie_aalp_5_bkwd_max_sdu =
901                                         ap->aal.v.aal5.backward_max_SDU_size;
902                         msg->msg_ie_aalp->ie_aalp_5_mode =
903                                         UNI_IE_AALP_A5_M_MSG;
904                         msg->msg_ie_aalp->ie_aalp_5_sscs_type =
905                                         ap->aal.v.aal5.SSCS_type;
906                         break;
907                 }
908         }
909
910         /*
911          * Set traffic descriptor attributes
912          */
913         if (ap->traffic.tag == T_ATM_PRESENT) {
914                 if (!msg->msg_ie_clrt) {
915                         msg->msg_ie_clrt = (struct ie_generic *)
916                                         atm_allocate(&unisig_iepool);
917                         if (msg->msg_ie_clrt == NULL) {
918                                 err = ENOMEM;
919                                 goto done;
920                         }
921                 }
922                 KM_COPY(&ie_clrt_absent,
923                                 &msg->msg_ie_clrt->ie_u.ie_clrt,
924                                 sizeof(ie_clrt_absent));
925                 msg->msg_ie_clrt->ie_ident = UNI_IE_CLRT;
926                 msg->msg_ie_clrt->ie_clrt_fwd_peak =
927                                 ap->traffic.v.forward.PCR_high_priority;
928                 msg->msg_ie_clrt->ie_clrt_fwd_peak_01 =
929                                 ap->traffic.v.forward.PCR_all_traffic;
930                 msg->msg_ie_clrt->ie_clrt_fwd_sust =
931                                 ap->traffic.v.forward.SCR_high_priority;
932                 msg->msg_ie_clrt->ie_clrt_fwd_sust_01 =
933                                 ap->traffic.v.forward.SCR_all_traffic;
934                 msg->msg_ie_clrt->ie_clrt_fwd_burst =
935                                 ap->traffic.v.forward.MBS_high_priority;
936                 msg->msg_ie_clrt->ie_clrt_fwd_burst_01 =
937                                 ap->traffic.v.forward.MBS_all_traffic;
938                 msg->msg_ie_clrt->ie_clrt_bkwd_peak =
939                                 ap->traffic.v.backward.PCR_high_priority;
940                 msg->msg_ie_clrt->ie_clrt_bkwd_peak_01 =
941                                 ap->traffic.v.backward.PCR_all_traffic;
942                 msg->msg_ie_clrt->ie_clrt_bkwd_sust =
943                                 ap->traffic.v.backward.SCR_high_priority;
944                 msg->msg_ie_clrt->ie_clrt_bkwd_sust_01 =
945                                 ap->traffic.v.backward.SCR_all_traffic;
946                 msg->msg_ie_clrt->ie_clrt_bkwd_burst =
947                                 ap->traffic.v.backward.MBS_high_priority;
948                 msg->msg_ie_clrt->ie_clrt_bkwd_burst_01 =
949                                 ap->traffic.v.backward.MBS_all_traffic;
950                 msg->msg_ie_clrt->ie_clrt_best_effort =
951                                 ap->traffic.v.best_effort;
952                 msg->msg_ie_clrt->ie_clrt_tm_options = 0;
953                 if (ap->traffic.v.forward.tagging) {
954                         msg->msg_ie_clrt->ie_clrt_tm_options |=
955                                         UNI_IE_CLRT_TM_FWD_TAG;
956                 }
957                 if (ap->traffic.v.backward.tagging) {
958                         msg->msg_ie_clrt->ie_clrt_tm_options |=
959                                         UNI_IE_CLRT_TM_BKWD_TAG;
960                 }
961                 if (msg->msg_ie_clrt->ie_clrt_tm_options == 0) {
962                         msg->msg_ie_clrt->ie_clrt_tm_options =
963                                         T_ATM_ABSENT;
964                 }
965         }
966
967         /*
968          * Set broadband bearer attributes
969          */
970         if (ap->bearer.tag == T_ATM_PRESENT) {
971                 if (!msg->msg_ie_bbcp) {
972                         msg->msg_ie_bbcp = (struct ie_generic *)
973                                         atm_allocate(&unisig_iepool);
974                         if (msg->msg_ie_bbcp == NULL) {
975                                 err = ENOMEM;
976                                 goto done;
977                         }
978                 }
979                 KM_COPY(&ie_bbcp_absent,
980                                 &msg->msg_ie_bbcp->ie_u.ie_bbcp,
981                                 sizeof(ie_bbcp_absent));
982                 msg->msg_ie_bbcp->ie_ident = UNI_IE_BBCP;
983                 msg->msg_ie_bbcp->ie_bbcp_bearer_class =
984                                 ap->bearer.v.bearer_class;
985                 msg->msg_ie_bbcp->ie_bbcp_traffic_type =
986                                 ap->bearer.v.traffic_type;
987                 msg->msg_ie_bbcp->ie_bbcp_timing_req =
988                                 ap->bearer.v.timing_requirements;
989                 msg->msg_ie_bbcp->ie_bbcp_clipping =
990                                 ap->bearer.v.clipping_susceptibility;
991                 msg->msg_ie_bbcp->ie_bbcp_conn_config =
992                                 ap->bearer.v.connection_configuration;
993         }
994
995         /*
996          * Set broadband high layer attributes
997          */
998         if (ap->bhli.tag == T_ATM_PRESENT) {
999                 if (!msg->msg_ie_bhli) {
1000                         msg->msg_ie_bhli = (struct ie_generic *)
1001                                         atm_allocate(&unisig_iepool);
1002                         if (msg->msg_ie_bhli == NULL) {
1003                                 err = ENOMEM;
1004                                 goto done;
1005                         }
1006                 }
1007                 KM_COPY(&ie_bhli_absent,
1008                                 &msg->msg_ie_bhli->ie_u.ie_bhli,
1009                                 sizeof(ie_bhli_absent));
1010                 msg->msg_ie_bhli->ie_ident = UNI_IE_BHLI;
1011                 msg->msg_ie_bhli->ie_bhli_type = ap->bhli.v.ID_type;
1012                 switch (ap->bhli.v.ID_type) {
1013                 case T_ATM_ISO_APP_ID:
1014                         KM_COPY(ap->bhli.v.ID.ISO_ID,
1015                                         msg->msg_ie_bhli->ie_bhli_info,
1016                                         sizeof(ap->bhli.v.ID.ISO_ID));
1017                         break;
1018                 case T_ATM_USER_APP_ID:
1019                         KM_COPY(ap->bhli.v.ID.user_defined_ID,
1020                                         msg->msg_ie_bhli->ie_bhli_info,
1021                                         sizeof(ap->bhli.v.ID.user_defined_ID));
1022                         break;
1023                 case T_ATM_VENDOR_APP_ID:
1024                         KM_COPY(ap->bhli.v.ID.vendor_ID.OUI,
1025                                         msg->msg_ie_bhli->ie_bhli_info,
1026                                         sizeof(ap->bhli.v.ID.vendor_ID.OUI));
1027                         KM_COPY(ap->bhli.v.ID.vendor_ID.app_ID,
1028                                         &msg->msg_ie_bhli->ie_bhli_info[sizeof(ap->bhli.v.ID.vendor_ID.OUI)-1],
1029                                         sizeof(ap->bhli.v.ID.vendor_ID.app_ID));
1030                         break;
1031                 }
1032         }
1033
1034         /*
1035          * Set Broadband low layer, user layer 2 and 3 attributes
1036          */
1037         if (ap->blli.tag_l2 == T_ATM_PRESENT ||
1038                         ap->blli.tag_l3 == T_ATM_PRESENT) {
1039                 if (!msg->msg_ie_blli) {
1040                         msg->msg_ie_blli = (struct ie_generic *)
1041                                         atm_allocate(&unisig_iepool);
1042                         if (msg->msg_ie_blli == NULL) {
1043                                 err = ENOMEM;
1044                                 goto done;
1045                         }
1046                 }
1047                 KM_COPY(&ie_blli_absent,
1048                                 &msg->msg_ie_blli->ie_u.ie_blli,
1049                                 sizeof(ie_blli_absent));
1050                 msg->msg_ie_blli->ie_ident = UNI_IE_BLLI;
1051
1052                 if (ap->blli.tag_l2 == T_ATM_PRESENT) {
1053                         switch(ap->blli.v.layer_2_protocol.ID_type) {
1054                         case T_ATM_SIMPLE_ID:
1055                                 msg->msg_ie_blli->ie_blli_l2_id =
1056                                                 ap->blli.v.layer_2_protocol.ID.simple_ID;
1057                                 break;
1058                         case T_ATM_USER_ID:
1059                                 msg->msg_ie_blli->ie_blli_l2_id =
1060                                                 UNI_IE_BLLI_L2P_USER;
1061                                 msg->msg_ie_blli->ie_blli_l2_user_proto =
1062                                                 ap->blli.v.layer_2_protocol.ID.user_defined_ID;
1063                                 break;
1064                         }
1065                         if (ap->blli.v.layer_2_protocol.ID_type !=
1066                                         T_ATM_ABSENT) {
1067                                 msg->msg_ie_blli->ie_blli_l2_mode =
1068                                                 ap->blli.v.layer_2_protocol.mode;
1069                                 msg->msg_ie_blli->ie_blli_l2_window =
1070                                                 ap->blli.v.layer_2_protocol.window_size;
1071                         }
1072                 }
1073
1074                 if (ap->blli.tag_l3 == T_ATM_PRESENT) {
1075                         switch (ap->blli.v.layer_3_protocol.ID_type) {
1076                         case T_ATM_SIMPLE_ID:
1077                                 msg->msg_ie_blli->ie_blli_l3_id =
1078                                                 ap->blli.v.layer_3_protocol.ID.simple_ID;
1079                                 break;
1080
1081                         case T_ATM_IPI_ID:
1082                                 msg->msg_ie_blli->ie_blli_l3_id =
1083                                                 UNI_IE_BLLI_L3P_ISO9577;
1084                                 msg->msg_ie_blli->ie_blli_l3_ipi =
1085                                                 ap->blli.v.layer_3_protocol.ID.IPI_ID;
1086                                 break;
1087
1088                         case T_ATM_SNAP_ID:
1089                                 msg->msg_ie_blli->ie_blli_l3_id =
1090                                                 UNI_IE_BLLI_L3P_ISO9577;
1091                                 msg->msg_ie_blli->ie_blli_l3_ipi =
1092                                                 UNI_IE_BLLI_L3IPI_SNAP;
1093                                 KM_COPY(ap->blli.v.layer_3_protocol.ID.SNAP_ID.OUI,
1094                                                 msg->msg_ie_blli->ie_blli_l3_oui,
1095                                                 sizeof(msg->msg_ie_blli->ie_blli_l3_oui));
1096                                 KM_COPY(ap->blli.v.layer_3_protocol.ID.SNAP_ID.PID,
1097                                                 msg->msg_ie_blli->ie_blli_l3_pid,
1098                                                 sizeof(msg->msg_ie_blli->ie_blli_l3_pid));
1099                                 break;
1100
1101                         case T_ATM_USER_ID:
1102                                 msg->msg_ie_blli->ie_blli_l3_id =
1103                                                 UNI_IE_BLLI_L3P_USER;
1104                                 msg->msg_ie_blli->ie_blli_l3_user_proto =
1105                                                 ap->blli.v.layer_3_protocol.ID.user_defined_ID;
1106                                 break;
1107                         }
1108                         if (ap->blli.v.layer_3_protocol.ID_type
1109                                         != T_ATM_ABSENT) {
1110                                 msg->msg_ie_blli->ie_blli_l3_mode =
1111                                                 ap->blli.v.layer_3_protocol.mode;
1112                                 msg->msg_ie_blli->ie_blli_l3_packet_size =
1113                                                 ap->blli.v.layer_3_protocol.packet_size;
1114                                 msg->msg_ie_blli->ie_blli_l3_window =
1115                                                 ap->blli.v.layer_3_protocol.window_size;
1116                         }
1117                 }
1118         }
1119
1120         /*
1121          * Set the called party address and subaddress
1122          */
1123         if (ap->called.tag == T_ATM_PRESENT) {
1124                 if (!msg->msg_ie_cdad) {
1125                         msg->msg_ie_cdad = (struct ie_generic *)
1126                                         atm_allocate(&unisig_iepool);
1127                         if (msg->msg_ie_cdad == NULL) {
1128                                 err = ENOMEM;
1129                                 goto done;
1130                         }
1131                 }
1132                 KM_COPY(&ie_cdad_absent,
1133                                 &msg->msg_ie_cdad->ie_u.ie_cdad,
1134                                 sizeof(ie_cdad_absent));
1135                 msg->msg_ie_cdad->ie_ident = UNI_IE_CDAD;
1136                 ATM_ADDR_COPY(&ap->called.addr,
1137                                 &msg->msg_ie_cdad->ie_cdad_addr);
1138
1139                 if (ap->called.subaddr.address_format != T_ATM_ABSENT) {
1140                         if (!msg->msg_ie_cdsa) {
1141                                 msg->msg_ie_cdsa = (struct ie_generic *)
1142                                                 atm_allocate(&unisig_iepool);
1143                                 if (msg->msg_ie_cdsa == NULL) {
1144                                         err = ENOMEM;
1145                                         goto done;
1146                                 }
1147                         }
1148                         KM_COPY(&ie_cdsa_absent,
1149                                         &msg->msg_ie_cdsa->ie_u.ie_cdsa,
1150                                         sizeof(ie_cdsa_absent));
1151                         msg->msg_ie_cdsa->ie_ident = UNI_IE_CDSA;
1152                         ATM_ADDR_COPY(&ap->called.subaddr,
1153                                         &msg->msg_ie_cdsa->ie_cdsa_addr);
1154                 }
1155         }
1156
1157         /*
1158          * Set the calling party address and subaddress
1159          */
1160
1161         if (ap->calling.tag == T_ATM_PRESENT) {
1162                 if (!msg->msg_ie_cgad) {
1163                         msg->msg_ie_cgad = (struct ie_generic *)
1164                                         atm_allocate(&unisig_iepool);
1165                         if (msg->msg_ie_cgad == NULL) {
1166                                 err = ENOMEM;
1167                                 goto done;
1168                         }
1169                 }
1170                 KM_COPY(&ie_cgad_absent,
1171                                 &msg->msg_ie_cgad->ie_u.ie_cgad,
1172                                 sizeof(ie_cgad_absent));
1173                 msg->msg_ie_cgsa->ie_ident = UNI_IE_CGSA;
1174                 ATM_ADDR_COPY(&ap->calling.addr,
1175                                 &msg->msg_ie_cgad->ie_cgad_addr);
1176
1177                 if (ap->calling.subaddr.address_format !=
1178                                 T_ATM_ABSENT) {
1179                         if (!msg->msg_ie_cgsa) {
1180                                 msg->msg_ie_cgsa = (struct ie_generic *)
1181                                                 atm_allocate(&unisig_iepool);
1182                                 if (msg->msg_ie_cgsa == NULL) {
1183                                         err = ENOMEM;
1184                                         goto done;
1185                                 }
1186                         }
1187                         KM_COPY(&ie_cgsa_absent,
1188                                         &msg->msg_ie_cgsa->ie_u.ie_cgsa,
1189                                         sizeof(ie_cgsa_absent));
1190                         msg->msg_ie_cgsa->ie_ident = UNI_IE_CGSA;
1191                         ATM_ADDR_COPY(&ap->calling.subaddr,
1192                                         &msg->msg_ie_cgsa->ie_cgsa_addr);
1193                 }
1194         }
1195
1196         /*
1197          * Set quality of service attributes
1198          */
1199         if (ap->qos.tag == T_ATM_PRESENT) {
1200                 if (!msg->msg_ie_qosp) {
1201                         msg->msg_ie_qosp = (struct ie_generic *)
1202                                         atm_allocate(&unisig_iepool);
1203                         if (msg->msg_ie_qosp == NULL) {
1204                                 err = ENOMEM;
1205                                 goto done;
1206                         }
1207                 }
1208                 KM_COPY(&ie_qosp_absent,
1209                                 &msg->msg_ie_qosp->ie_u.ie_qosp,
1210                                 sizeof(ie_qosp_absent));
1211                 msg->msg_ie_qosp->ie_ident = UNI_IE_QOSP;
1212                 if (usp->us_proto == ATM_SIG_UNI30)
1213                         msg->msg_ie_qosp->ie_coding = UNI_IE_CODE_STD;
1214                 else if ((ap->qos.v.forward.qos_class == 
1215                                         T_ATM_QOS_CLASS_0) || 
1216                            (ap->qos.v.backward.qos_class == 
1217                                         T_ATM_QOS_CLASS_0))
1218                         msg->msg_ie_qosp->ie_coding = UNI_IE_CODE_CCITT;
1219                 else
1220                         msg->msg_ie_qosp->ie_coding = ap->qos.v.coding_standard;
1221                 msg->msg_ie_qosp->ie_qosp_fwd_class =
1222                                 ap->qos.v.forward.qos_class;
1223                 msg->msg_ie_qosp->ie_qosp_bkwd_class =
1224                                 ap->qos.v.backward.qos_class;
1225         }
1226
1227         /*
1228          * Set transit network attributes
1229          */
1230         if (ap->transit.tag == T_ATM_PRESENT &&
1231                                 ap->transit.v.length != 0) {
1232                 if (!msg->msg_ie_trnt) {
1233                         msg->msg_ie_trnt = (struct ie_generic *)
1234                                         atm_allocate(&unisig_iepool);
1235                         if (msg->msg_ie_trnt == NULL) {
1236                                 err = ENOMEM;
1237                                 goto done;
1238                         }
1239                 }
1240                 KM_COPY(&ie_trnt_absent,
1241                                 &msg->msg_ie_trnt->ie_u.ie_trnt,
1242                                 sizeof(ie_trnt_absent));
1243                 msg->msg_ie_trnt->ie_ident = UNI_IE_TRNT;
1244                 msg->msg_ie_trnt->ie_trnt_id_type =
1245                                 UNI_IE_TRNT_IDT_NATL;
1246                 msg->msg_ie_trnt->ie_trnt_id_plan =
1247                                 UNI_IE_TRNT_IDP_CIC;
1248                 KM_COPY(ap->transit.v.network_id,
1249                                 msg->msg_ie_trnt->ie_trnt_id,
1250                                 ap->transit.v.length);
1251         }
1252
1253         /*
1254          * Set cause code
1255          */
1256         if (ap->cause.tag == T_ATM_PRESENT) {
1257                 if (!msg->msg_ie_caus) {
1258                         msg->msg_ie_caus = (struct ie_generic *)
1259                                         atm_allocate(&unisig_iepool);
1260                         if (msg->msg_ie_caus == NULL) {
1261                                 err = ENOMEM;
1262                                 goto done;
1263                         }
1264                 }
1265                 KM_COPY(&ie_caus_absent,
1266                                 &msg->msg_ie_caus->ie_u.ie_caus,
1267                                 sizeof(ie_caus_absent));
1268                 msg->msg_ie_caus->ie_ident = UNI_IE_CAUS;
1269                 msg->msg_ie_caus->ie_coding =
1270                                 ap->cause.v.coding_standard;
1271                 msg->msg_ie_caus->ie_caus_loc =
1272                                 ap->cause.v.location;
1273                 msg->msg_ie_caus->ie_caus_cause =
1274                                 ap->cause.v.cause_value;
1275
1276                 /*
1277                  * Don't copy the diagnostics from the attribute
1278                  * block, as there's no way to tell how much of
1279                  * the diagnostic field is relevant
1280                  */
1281                 msg->msg_ie_caus->ie_caus_diag_len = 0;
1282         }
1283
1284 done:
1285         return(err);
1286 }