kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / netproto / atm / uni / uniarp_output.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/uniarp_output.c,v 1.3 1999/08/28 00:49:03 peter Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/uni/uniarp_output.c,v 1.3 2003/08/07 21:17:35 dillon Exp $
28  */
29
30 /*
31  * ATM Forum UNI Support
32  * ---------------------
33  *
34  * UNI ATMARP support (RFC1577) - Output packet processing
35  *
36  */
37
38 #include <netatm/kern_include.h>
39
40 #include <netatm/ipatm/ipatm_var.h>
41 #include <netatm/ipatm/ipatm_serv.h>
42 #include "uniip_var.h"
43
44 /*
45  * Issue an ATMARP Request PDU
46  * 
47  * Arguments:
48  *      uip     pointer to IP interface
49  *      tip     pointer to target IP address
50  *
51  * Returns:
52  *      0       PDU was successfully sent
53  *      else    unable to send PDU
54  *
55  */
56 int
57 uniarp_arp_req(uip, tip)
58         struct uniip    *uip;
59         struct in_addr  *tip;
60 {
61         KBuffer         *m;
62         struct atmarp_hdr       *ahp;
63         struct atm_nif  *nip;
64         struct ip_nif   *inp;
65         struct ipvcc    *ivp;
66         struct siginst  *sip;
67         char            *cp;
68         int             len, err;
69
70         inp = uip->uip_ipnif;
71         nip = inp->inf_nif;
72         sip = inp->inf_nif->nif_pif->pif_siginst;
73
74         /*
75          * Figure out how long pdu is going to be
76          */
77         len = sizeof(struct atmarp_hdr) + (2 * sizeof(struct in_addr));
78         switch (sip->si_addr.address_format) {
79         case T_ATM_ENDSYS_ADDR:
80                 len += sip->si_addr.address_length;
81                 break;
82
83         case T_ATM_E164_ADDR:
84                 len += sip->si_addr.address_length;
85                 if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR)
86                         len += sip->si_subaddr.address_length;
87                 break;
88         }
89         
90         /*
91          * Get a buffer for pdu
92          */
93         KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA);
94         if (m == NULL)
95                 return (1);
96
97         /*
98          * Place aligned pdu at end of buffer
99          */
100         KB_TAILALIGN(m, len);
101         KB_DATASTART(m, ahp, struct atmarp_hdr *);
102
103         /*
104          * Setup variable fields pointer
105          */
106         cp = (char *)ahp + sizeof(struct atmarp_hdr);
107
108         /*
109          * Build fields
110          */
111         ahp->ah_hrd = htons(ARP_ATMFORUM);
112         ahp->ah_pro = htons(ETHERTYPE_IP);
113         len = sip->si_addr.address_length;
114         switch (sip->si_addr.address_format) {
115         case T_ATM_ENDSYS_ADDR:
116                 ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
117
118                 /* ah_sha */
119                 KM_COPY(sip->si_addr.address, cp, len - 1);
120                 ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
121                 cp += len;
122
123                 ahp->ah_sstl = 0;
124                 break;
125
126         case T_ATM_E164_ADDR:
127                 ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
128
129                 /* ah_sha */
130                 KM_COPY(sip->si_addr.address, cp, len);
131                 cp += len;
132
133                 if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) {
134                         len = sip->si_subaddr.address_length;
135                         ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
136
137                         /* ah_ssa */
138                         KM_COPY(sip->si_subaddr.address, cp, len - 1);
139                         ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
140                         cp += len;
141                 } else
142                         ahp->ah_sstl = 0;
143                 break;
144
145         default:
146                 ahp->ah_shtl = 0;
147                 ahp->ah_sstl = 0;
148         }
149
150         ahp->ah_op = htons(ARP_REQUEST);
151         ahp->ah_spln = sizeof(struct in_addr);
152
153         /* ah_spa */
154         KM_COPY((caddr_t)&(IA_SIN(inp->inf_addr)->sin_addr), cp, 
155                 sizeof(struct in_addr));
156         cp += sizeof(struct in_addr);
157
158         ahp->ah_thtl = 0;
159         ahp->ah_tstl = 0;
160
161         ahp->ah_tpln = sizeof(struct in_addr);
162
163         /* ah_tpa */
164         KM_COPY((caddr_t)tip, cp, sizeof(struct in_addr));
165
166         /*
167          * Finally, send the pdu to the ATMARP server
168          */
169         ivp = uip->uip_arpsvrvcc;
170         if (uniarp_print)
171                 uniarp_pdu_print(ivp, m, "send");
172         err = atm_cm_cpcs_data(ivp->iv_arpconn, m);
173         if (err) {
174                 /*
175                  * Didn't make it
176                  */
177                 KB_FREEALL(m);
178                 return (1);
179         }
180
181         return (0);
182 }
183
184
185 /*
186  * Issue an ATMARP Response PDU
187  * 
188  * Arguments:
189  *      uip     pointer to IP interface
190  *      amp     pointer to source map entry
191  *      tip     pointer to target IP address
192  *      tatm    pointer to target ATM address
193  *      tsub    pointer to target ATM subaddress
194  *      ivp     pointer to vcc over which to send pdu
195  *
196  * Returns:
197  *      0       PDU was successfully sent
198  *      else    unable to send PDU
199  *
200  */
201 int
202 uniarp_arp_rsp(uip, amp, tip, tatm, tsub, ivp)
203         struct uniip    *uip;
204         struct arpmap   *amp;
205         struct in_addr  *tip;
206         Atm_addr        *tatm;
207         Atm_addr        *tsub;
208         struct ipvcc    *ivp;
209 {
210         KBuffer         *m;
211         struct atmarp_hdr       *ahp;
212         char            *cp;
213         int             len, err;
214
215         /*
216          * Figure out how long pdu is going to be
217          */
218         len = sizeof(struct atmarp_hdr) + (2 * sizeof(struct in_addr));
219         switch (amp->am_dstatm.address_format) {
220         case T_ATM_ENDSYS_ADDR:
221                 len += amp->am_dstatm.address_length;
222                 break;
223
224         case T_ATM_E164_ADDR:
225                 len += amp->am_dstatm.address_length;
226                 if (amp->am_dstatmsub.address_format == T_ATM_ENDSYS_ADDR)
227                         len += amp->am_dstatmsub.address_length;
228                 break;
229         }
230
231         switch (tatm->address_format) {
232         case T_ATM_ENDSYS_ADDR:
233                 len += tatm->address_length;
234                 break;
235
236         case T_ATM_E164_ADDR:
237                 len += tatm->address_length;
238                 if (tsub->address_format == T_ATM_ENDSYS_ADDR)
239                         len += tsub->address_length;
240                 break;
241         }
242
243         /*
244          * Get a buffer for pdu
245          */
246         KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA);
247         if (m == NULL)
248                 return (1);
249
250         /*
251          * Place aligned pdu at end of buffer
252          */
253         KB_TAILALIGN(m, len);
254         KB_DATASTART(m, ahp, struct atmarp_hdr *);
255
256         /*
257          * Setup variable fields pointer
258          */
259         cp = (char *)ahp + sizeof(struct atmarp_hdr);
260
261         /*
262          * Build fields
263          */
264         ahp->ah_hrd = htons(ARP_ATMFORUM);
265         ahp->ah_pro = htons(ETHERTYPE_IP);
266         len = amp->am_dstatm.address_length;
267         switch (amp->am_dstatm.address_format) {
268         case T_ATM_ENDSYS_ADDR:
269                 ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
270
271                 /* ah_sha */
272                 KM_COPY(amp->am_dstatm.address, cp, len);
273                 cp += len;
274
275                 ahp->ah_sstl = 0;
276                 break;
277
278         case T_ATM_E164_ADDR:
279                 ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
280
281                 /* ah_sha */
282                 KM_COPY(amp->am_dstatm.address, cp, len);
283                 cp += len;
284
285                 if (amp->am_dstatmsub.address_format == T_ATM_ENDSYS_ADDR) {
286                         len = amp->am_dstatmsub.address_length;
287                         ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
288
289                         /* ah_ssa */
290                         KM_COPY(amp->am_dstatmsub.address, cp, len);
291                         cp += len;
292                 } else
293                         ahp->ah_sstl = 0;
294                 break;
295
296         default:
297                 ahp->ah_shtl = 0;
298                 ahp->ah_sstl = 0;
299         }
300
301         ahp->ah_op = htons(ARP_REPLY);
302         ahp->ah_spln = sizeof(struct in_addr);
303
304         /* ah_spa */
305         KM_COPY((caddr_t)&amp->am_dstip, cp, sizeof(struct in_addr));
306         cp += sizeof(struct in_addr);
307
308         len = tatm->address_length;
309         switch (tatm->address_format) {
310         case T_ATM_ENDSYS_ADDR:
311                 ahp->ah_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
312
313                 /* ah_tha */
314                 KM_COPY(tatm->address, cp, len);
315                 cp += len;
316
317                 ahp->ah_tstl = 0;
318                 break;
319
320         case T_ATM_E164_ADDR:
321                 ahp->ah_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
322
323                 /* ah_tha */
324                 KM_COPY(tatm->address, cp, len);
325                 cp += len;
326
327                 if (tsub->address_format == T_ATM_ENDSYS_ADDR) {
328                         len = tsub->address_length;
329                         ahp->ah_tstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
330
331                         /* ah_tsa */
332                         KM_COPY(tsub->address, cp, len);
333                         cp += len;
334                 } else
335                         ahp->ah_tstl = 0;
336                 break;
337
338         default:
339                 ahp->ah_thtl = 0;
340                 ahp->ah_tstl = 0;
341         }
342
343         ahp->ah_tpln = sizeof(struct in_addr);
344
345         /* ah_tpa */
346         KM_COPY((caddr_t)tip, cp, sizeof(struct in_addr));
347
348         /*
349          * Finally, send the pdu to the vcc peer
350          */
351         if (uniarp_print)
352                 uniarp_pdu_print(ivp, m, "send");
353         err = atm_cm_cpcs_data(ivp->iv_arpconn, m);
354         if (err) {
355                 /*
356                  * Didn't make it
357                  */
358                 KB_FREEALL(m);
359                 return (1);
360         }
361
362         return (0);
363 }
364
365
366 /*
367  * Issue an ATMARP NAK PDU
368  * 
369  * Arguments:
370  *      uip     pointer to IP interface
371  *      m       pointer to ATMARP_REQ buffer chain
372  *      ivp     pointer to vcc over which to send pdu
373  *
374  * Returns:
375  *      0       PDU was successfully sent
376  *      else    unable to send PDU
377  *
378  */
379 int
380 uniarp_arp_nak(uip, m, ivp)
381         struct uniip    *uip;
382         KBuffer         *m;
383         struct ipvcc    *ivp;
384 {
385         struct atmarp_hdr       *ahp;
386         int             err;
387
388         /*
389          * Get the fixed fields together
390          */
391         if (KB_LEN(m) < sizeof(struct atmarp_hdr)) {
392                 KB_PULLUP(m, sizeof(struct atmarp_hdr), m);
393                 if (m == NULL)
394                         return (1);
395         }
396         KB_DATASTART(m, ahp, struct atmarp_hdr *);
397
398         /*
399          * Set new op-code
400          */
401         ahp->ah_op = htons(ARP_NAK);
402
403         /*
404          * Finally, send the pdu to the vcc peer
405          */
406         if (uniarp_print)
407                 uniarp_pdu_print(ivp, m, "send");
408         err = atm_cm_cpcs_data(ivp->iv_arpconn, m);
409         if (err) {
410                 /*
411                  * Didn't make it
412                  */
413                 KB_FREEALL(m);
414                 return (1);
415         }
416
417         return (0);
418 }
419
420
421 /*
422  * Issue an InATMARP Request PDU
423  * 
424  * Arguments:
425  *      uip     pointer to IP interface
426  *      tatm    pointer to target ATM address
427  *      tsub    pointer to target ATM subaddress
428  *      ivp     pointer to vcc over which to send pdu
429  *
430  * Returns:
431  *      0       PDU was successfully sent
432  *      else    unable to send PDU
433  *
434  */
435 int
436 uniarp_inarp_req(uip, tatm, tsub, ivp)
437         struct uniip    *uip;
438         Atm_addr        *tatm;
439         Atm_addr        *tsub;
440         struct ipvcc    *ivp;
441 {
442         KBuffer         *m;
443         struct atmarp_hdr       *ahp;
444         struct atm_nif  *nip;
445         struct ip_nif   *inp;
446         struct siginst  *sip;
447         char            *cp;
448         int             len, err;
449
450         inp = uip->uip_ipnif;
451         nip = inp->inf_nif;
452         sip = inp->inf_nif->nif_pif->pif_siginst;
453
454         /*
455          * Figure out how long pdu is going to be
456          */
457         len = sizeof(struct atmarp_hdr) + sizeof(struct in_addr);
458         switch (sip->si_addr.address_format) {
459         case T_ATM_ENDSYS_ADDR:
460                 len += sip->si_addr.address_length;
461                 break;
462
463         case T_ATM_E164_ADDR:
464                 len += sip->si_addr.address_length;
465                 if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR)
466                         len += sip->si_subaddr.address_length;
467                 break;
468         }
469
470         switch (tatm->address_format) {
471         case T_ATM_ENDSYS_ADDR:
472                 len += tatm->address_length;
473                 break;
474
475         case T_ATM_E164_ADDR:
476                 len += tatm->address_length;
477                 if (tsub->address_format == T_ATM_ENDSYS_ADDR)
478                         len += tsub->address_length;
479                 break;
480         }
481
482         /*
483          * Get a buffer for pdu
484          */
485         KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA);
486         if (m == NULL)
487                 return (1);
488
489         /*
490          * Place aligned pdu at end of buffer
491          */
492         KB_TAILALIGN(m, len);
493         KB_DATASTART(m, ahp, struct atmarp_hdr *);
494
495         /*
496          * Setup variable fields pointer
497          */
498         cp = (char *)ahp + sizeof(struct atmarp_hdr);
499
500         /*
501          * Build fields
502          */
503         ahp->ah_hrd = htons(ARP_ATMFORUM);
504         ahp->ah_pro = htons(ETHERTYPE_IP);
505         len = sip->si_addr.address_length;
506         switch (sip->si_addr.address_format) {
507         case T_ATM_ENDSYS_ADDR:
508                 ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
509
510                 /* ah_sha */
511                 KM_COPY(sip->si_addr.address, cp, len - 1);
512                 ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
513                 cp += len;
514
515                 ahp->ah_sstl = 0;
516                 break;
517
518         case T_ATM_E164_ADDR:
519                 ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
520
521                 /* ah_sha */
522                 KM_COPY(sip->si_addr.address, cp, len);
523                 cp += len;
524
525                 if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) {
526                         len = sip->si_subaddr.address_length;
527                         ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
528
529                         /* ah_ssa */
530                         KM_COPY(sip->si_subaddr.address, cp, len - 1);
531                         ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
532                         cp += len;
533                 } else
534                         ahp->ah_sstl = 0;
535                 break;
536
537         default:
538                 ahp->ah_shtl = 0;
539                 ahp->ah_sstl = 0;
540         }
541
542         ahp->ah_op = htons(INARP_REQUEST);
543         ahp->ah_spln = sizeof(struct in_addr);
544
545         /* ah_spa */
546         KM_COPY((caddr_t)&(IA_SIN(inp->inf_addr)->sin_addr), cp, 
547                 sizeof(struct in_addr));
548         cp += sizeof(struct in_addr);
549
550         len = tatm->address_length;
551         switch (tatm->address_format) {
552         case T_ATM_ENDSYS_ADDR:
553                 ahp->ah_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
554
555                 /* ah_tha */
556                 KM_COPY(tatm->address, cp, len);
557                 cp += len;
558
559                 ahp->ah_tstl = 0;
560                 break;
561
562         case T_ATM_E164_ADDR:
563                 ahp->ah_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
564
565                 /* ah_tha */
566                 KM_COPY(tatm->address, cp, len);
567                 cp += len;
568
569                 if (tsub->address_format == T_ATM_ENDSYS_ADDR) {
570                         len = tsub->address_length;
571                         ahp->ah_tstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
572
573                         /* ah_tsa */
574                         KM_COPY(tsub->address, cp, len);
575                         cp += len;
576                 } else
577                         ahp->ah_tstl = 0;
578                 break;
579
580         default:
581                 ahp->ah_thtl = 0;
582                 ahp->ah_tstl = 0;
583         }
584
585         ahp->ah_tpln = 0;
586
587         /*
588          * Finally, send the pdu to the vcc peer
589          */
590         if (uniarp_print)
591                 uniarp_pdu_print(ivp, m, "send");
592         err = atm_cm_cpcs_data(ivp->iv_arpconn, m);
593         if (err) {
594                 /*
595                  * Didn't make it
596                  */
597                 KB_FREEALL(m);
598                 return (1);
599         }
600
601         return (0);
602 }
603
604
605 /*
606  * Issue an InATMARP Response PDU
607  * 
608  * Arguments:
609  *      uip     pointer to IP interface
610  *      tip     pointer to target IP address
611  *      tatm    pointer to target ATM address
612  *      tsub    pointer to target ATM subaddress
613  *      ivp     pointer to vcc over which to send pdu
614  *
615  * Returns:
616  *      0       PDU was successfully sent
617  *      else    unable to send PDU
618  *
619  */
620 int
621 uniarp_inarp_rsp(uip, tip, tatm, tsub, ivp)
622         struct uniip    *uip;
623         struct in_addr  *tip;
624         Atm_addr        *tatm;
625         Atm_addr        *tsub;
626         struct ipvcc    *ivp;
627 {
628         KBuffer         *m;
629         struct atmarp_hdr       *ahp;
630         struct atm_nif  *nip;
631         struct ip_nif   *inp;
632         struct siginst  *sip;
633         char            *cp;
634         int             len, err;
635
636         inp = uip->uip_ipnif;
637         nip = inp->inf_nif;
638         sip = inp->inf_nif->nif_pif->pif_siginst;
639
640         /*
641          * Figure out how long pdu is going to be
642          */
643         len = sizeof(struct atmarp_hdr) + (2 * sizeof(struct in_addr));
644         switch (sip->si_addr.address_format) {
645         case T_ATM_ENDSYS_ADDR:
646                 len += sip->si_addr.address_length;
647                 break;
648
649         case T_ATM_E164_ADDR:
650                 len += sip->si_addr.address_length;
651                 if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR)
652                         len += sip->si_subaddr.address_length;
653                 break;
654         }
655
656         switch (tatm->address_format) {
657         case T_ATM_ENDSYS_ADDR:
658                 len += tatm->address_length;
659                 break;
660
661         case T_ATM_E164_ADDR:
662                 len += tatm->address_length;
663                 if (tsub->address_format == T_ATM_ENDSYS_ADDR)
664                         len += tsub->address_length;
665                 break;
666         }
667
668         /*
669          * Get a buffer for pdu
670          */
671         KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA);
672         if (m == NULL)
673                 return (1);
674
675         /*
676          * Place aligned pdu at end of buffer
677          */
678         KB_TAILALIGN(m, len);
679         KB_DATASTART(m, ahp, struct atmarp_hdr *);
680
681         /*
682          * Setup variable fields pointer
683          */
684         cp = (char *)ahp + sizeof(struct atmarp_hdr);
685
686         /*
687          * Build fields
688          */
689         ahp->ah_hrd = htons(ARP_ATMFORUM);
690         ahp->ah_pro = htons(ETHERTYPE_IP);
691         len = sip->si_addr.address_length;
692         switch (sip->si_addr.address_format) {
693         case T_ATM_ENDSYS_ADDR:
694                 ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
695
696                 /* ah_sha */
697                 KM_COPY(sip->si_addr.address, cp, len - 1);
698                 ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
699                 cp += len;
700
701                 ahp->ah_sstl = 0;
702                 break;
703
704         case T_ATM_E164_ADDR:
705                 ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
706
707                 /* ah_sha */
708                 KM_COPY(sip->si_addr.address, cp, len);
709                 cp += len;
710
711                 if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) {
712                         len = sip->si_subaddr.address_length;
713                         ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
714
715                         /* ah_ssa */
716                         KM_COPY(sip->si_subaddr.address, cp, len - 1);
717                         ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
718                         cp += len;
719                 } else
720                         ahp->ah_sstl = 0;
721                 break;
722
723         default:
724                 ahp->ah_shtl = 0;
725                 ahp->ah_sstl = 0;
726         }
727
728         ahp->ah_op = htons(INARP_REPLY);
729         ahp->ah_spln = sizeof(struct in_addr);
730
731         /* ah_spa */
732         KM_COPY((caddr_t)&(IA_SIN(inp->inf_addr)->sin_addr), cp, 
733                 sizeof(struct in_addr));
734         cp += sizeof(struct in_addr);
735
736         len = tatm->address_length;
737         switch (tatm->address_format) {
738         case T_ATM_ENDSYS_ADDR:
739                 ahp->ah_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
740
741                 /* ah_tha */
742                 KM_COPY(tatm->address, cp, len);
743                 cp += len;
744
745                 ahp->ah_tstl = 0;
746                 break;
747
748         case T_ATM_E164_ADDR:
749                 ahp->ah_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
750
751                 /* ah_tha */
752                 KM_COPY(tatm->address, cp, len);
753                 cp += len;
754
755                 if (tsub->address_format == T_ATM_ENDSYS_ADDR) {
756                         len = tsub->address_length;
757                         ahp->ah_tstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
758
759                         /* ah_tsa */
760                         KM_COPY(tsub->address, cp, len);
761                         cp += len;
762                 } else
763                         ahp->ah_tstl = 0;
764                 break;
765
766         default:
767                 ahp->ah_thtl = 0;
768                 ahp->ah_tstl = 0;
769         }
770
771         ahp->ah_tpln = sizeof(struct in_addr);
772
773         /* ah_tpa */
774         KM_COPY((caddr_t)tip, cp, sizeof(struct in_addr));
775
776         /*
777          * Finally, send the pdu to the vcc peer
778          */
779         if (uniarp_print)
780                 uniarp_pdu_print(ivp, m, "send");
781         err = atm_cm_cpcs_data(ivp->iv_arpconn, m);
782         if (err) {
783                 /*
784                  * Didn't make it
785                  */
786                 KB_FREEALL(m);
787                 return (1);
788         }
789
790         return (0);
791 }
792