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