Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / netproto / atm / ipatm / ipatm_load.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/ipatm/ipatm_load.c,v 1.6 2000/01/17 20:49:43 mks Exp $
27  *
28  */
29
30 /*
31  * IP Over ATM Support
32  * -------------------
33  *
34  * Support for running as a loadable kernel module
35  *
36  */
37
38 #ifndef ATM_IP_MODULE
39 #include "opt_atm.h"
40 #endif
41
42 #include <netatm/kern_include.h>
43
44 #include <netatm/ipatm/ipatm.h>
45 #include <netatm/ipatm/ipatm_var.h>
46
47 #ifndef lint
48 __RCSID("@(#) $FreeBSD: src/sys/netatm/ipatm/ipatm_load.c,v 1.6 2000/01/17 20:49:43 mks Exp $");
49 #endif
50
51
52 /*
53  * Global variables
54  */
55 int             ipatm_vccnt = 0;                
56 int             ipatm_vcidle = IPATM_VCIDLE;            
57 int             ipatm_print = 0;
58 u_long          last_map_ipdst = 0;
59 struct ipvcc*   last_map_ipvcc = NULL;
60
61 struct ip_nif   *ipatm_nif_head = NULL;
62
63 struct ipatm_stat       ipatm_stat = {0};
64
65 struct atm_time         ipatm_itimer = {0, 0};  /* VCC idle timer */
66
67 Atm_endpoint    ipatm_endpt = {
68         NULL,
69         ENDPT_IP,
70         ipatm_ioctl,
71         ipatm_getname,
72         ipatm_connected,
73         ipatm_cleared,
74         ipatm_incoming,
75         NULL,
76         NULL,
77         NULL,
78         ipatm_cpcs_data,
79         NULL,
80         NULL,
81         NULL,
82         NULL
83 };
84
85 struct sp_info  ipatm_vcpool = {
86         "ipatm vcc pool",               /* si_name */
87         sizeof(struct ipvcc),           /* si_blksiz */
88         10,                             /* si_blkcnt */
89         100                             /* si_maxallow */
90 };
91
92 struct sp_info  ipatm_nifpool = {
93         "ipatm nif pool",               /* si_name */
94         sizeof(struct ip_nif),          /* si_blksiz */
95         5,                              /* si_blkcnt */
96         52                              /* si_maxallow */
97 };
98
99
100 /*
101  * Local functions
102  */
103 static int      ipatm_start __P((void));
104 static int      ipatm_stop __P((void));
105
106
107 /*
108  * Local variables
109  */
110 static struct atm_ncm   ipatm_ncm = {
111         NULL,
112         AF_INET,
113         ipatm_ifoutput,
114         ipatm_nifstat
115 };
116
117 static struct ipatm_listener {
118         Atm_attributes  attr;
119         Atm_connection  *conn;
120 } ipatm_listeners[] = {
121 {
122         {       NULL,                   /* nif */
123                 CMAPI_CPCS,             /* api */
124                 0,                      /* api_init */
125                 0,                      /* headin */
126                 0,                      /* headout */
127                 {                       /* aal */
128                         T_ATM_PRESENT,
129                         ATM_AAL5
130                 },
131                 {                       /* traffic */
132                         T_ATM_PRESENT,
133                         {
134                                 {
135                                         T_ATM_ABSENT,
136                                         0,
137                                         T_ATM_ABSENT,
138                                         T_ATM_ABSENT,
139                                         T_ATM_ABSENT,
140                                         T_ATM_ABSENT,
141                                         T_NO
142                                 },
143                                 {
144                                         T_ATM_ABSENT,
145                                         0,
146                                         T_ATM_ABSENT,
147                                         T_ATM_ABSENT,
148                                         T_ATM_ABSENT,
149                                         T_ATM_ABSENT,
150                                         T_NO
151                                 },
152                                 T_YES
153                         },
154                 },
155                 {                       /* bearer */
156                         T_ATM_ANY
157                 },
158                 {                       /* bhli */
159                         T_ATM_ABSENT
160                 },
161                 {                       /* blli */
162                         T_ATM_PRESENT,
163                         T_ATM_ABSENT,
164                         {
165                                 {
166                                         T_ATM_SIMPLE_ID,
167                                 },
168                                 {
169                                         T_ATM_ABSENT
170                                 }
171                         }
172                 },
173                 {                       /* llc */
174                         T_ATM_PRESENT,
175                         {
176                                 T_ATM_LLC_SHARING,
177                                 IPATM_LLC_LEN,
178                                 IPATM_LLC_HDR
179                         }
180                 },
181                 {                       /* called */
182                         T_ATM_ANY
183                 },
184                 {                       /* calling */
185                         T_ATM_ANY
186                 },
187                 {                       /* qos */
188                         T_ATM_PRESENT,
189                         {
190                                 T_ATM_NETWORK_CODING,
191                                 {
192                                         T_ATM_QOS_CLASS_0,
193                                 },
194                                 {
195                                         T_ATM_QOS_CLASS_0
196                                 }
197                         }
198                 },
199                 {                       /* transit */
200                         T_ATM_ANY
201                 },
202                 {                       /* cause */
203                         T_ATM_ABSENT
204                 },
205         },
206         NULL
207 },
208 {
209         {       NULL,                   /* nif */
210                 CMAPI_CPCS,             /* api */
211                 0,                      /* api_init */
212                 0,                      /* headin */
213                 0,                      /* headout */
214                 {                       /* aal */
215                         T_ATM_PRESENT,
216                         ATM_AAL5
217                 },
218                 {                       /* traffic */
219                         T_ATM_PRESENT,
220                         {
221                                 {
222                                         T_ATM_ABSENT,
223                                         0,
224                                         T_ATM_ABSENT,
225                                         T_ATM_ABSENT,
226                                         T_ATM_ABSENT,
227                                         T_ATM_ABSENT,
228                                         T_NO
229                                 },
230                                 {
231                                         T_ATM_ABSENT,
232                                         0,
233                                         T_ATM_ABSENT,
234                                         T_ATM_ABSENT,
235                                         T_ATM_ABSENT,
236                                         T_ATM_ABSENT,
237                                         T_NO
238                                 },
239                                 T_YES
240                         },
241                 },
242                 {                       /* bearer */
243                         T_ATM_ANY
244                 },
245                 {                       /* bhli */
246                         T_ATM_ABSENT
247                 },
248                 {                       /* blli */
249                         T_ATM_ABSENT,
250                         T_ATM_ABSENT
251                 },
252                 {                       /* llc */
253                         T_ATM_ABSENT
254                 },
255                 {                       /* called */
256                         T_ATM_ANY
257                 },
258                 {                       /* calling */
259                         T_ATM_ANY
260                 },
261                 {                       /* qos */
262                         T_ATM_PRESENT,
263                         {
264                                 T_ATM_NETWORK_CODING,
265                                 {
266                                         T_ATM_QOS_CLASS_0,
267                                 },
268                                 {
269                                         T_ATM_QOS_CLASS_0
270                                 }
271                         }
272                 },
273                 {                       /* transit */
274                         T_ATM_ANY
275                 },
276                 {                       /* cause */
277                         T_ATM_ABSENT
278                 },
279         },
280         NULL
281 },
282 {
283         {       NULL,                   /* nif */
284                 CMAPI_CPCS,             /* api */
285                 0,                      /* api_init */
286                 0,                      /* headin */
287                 0,                      /* headout */
288                 {                       /* aal */
289                         T_ATM_PRESENT,
290                         ATM_AAL3_4
291                 },
292                 {                       /* traffic */
293                         T_ATM_PRESENT,
294                         {
295                                 {
296                                         T_ATM_ABSENT,
297                                         0,
298                                         T_ATM_ABSENT,
299                                         T_ATM_ABSENT,
300                                         T_ATM_ABSENT,
301                                         T_ATM_ABSENT,
302                                         T_NO
303                                 },
304                                 {
305                                         T_ATM_ABSENT,
306                                         0,
307                                         T_ATM_ABSENT,
308                                         T_ATM_ABSENT,
309                                         T_ATM_ABSENT,
310                                         T_ATM_ABSENT,
311                                         T_NO
312                                 },
313                                 T_YES
314                         },
315                 },
316                 {                       /* bearer */
317                         T_ATM_ANY
318                 },
319                 {                       /* bhli */
320                         T_ATM_ABSENT
321                 },
322                 {                       /* blli */
323                         T_ATM_ABSENT,
324                         T_ATM_ABSENT
325                 },
326                 {                       /* llc */
327                         T_ATM_ABSENT
328                 },
329                 {                       /* called */
330                         T_ATM_ANY
331                 },
332                 {                       /* calling */
333                         T_ATM_ANY
334                 },
335                 {                       /* qos */
336                         T_ATM_PRESENT,
337                         {
338                                 T_ATM_NETWORK_CODING,
339                                 {
340                                         T_ATM_QOS_CLASS_0,
341                                 },
342                                 {
343                                         T_ATM_QOS_CLASS_0
344                                 }
345                         }
346                 },
347                 {                       /* transit */
348                         T_ATM_ANY
349                 },
350                 {                       /* cause */
351                         T_ATM_ABSENT
352                 },
353         },
354         NULL
355 },
356 };
357
358 static struct t_atm_cause       ipatm_cause = {
359         T_ATM_ITU_CODING,
360         T_ATM_LOC_USER,
361         T_ATM_CAUSE_UNSPECIFIED_NORMAL,
362         {0, 0, 0, 0}
363 };
364
365
366 /*
367  * Initialize ipatm processing
368  * 
369  * This will be called during module loading.  We'll just register
370  * ourselves and wait for the packets to start flying.
371  *
372  * Arguments:
373  *      none
374  *
375  * Returns:
376  *      0       startup was successful 
377  *      errno   startup failed - reason indicated
378  *
379  */
380 static int
381 ipatm_start()
382 {
383         struct atm_pif  *pip;
384         struct atm_nif  *nip;
385         int     err, s, i;
386
387         /*
388          * Verify software version
389          */
390         if (atm_version != ATM_VERSION) {
391                 log(LOG_ERR, "version mismatch: ipatm=%d.%d kernel=%d.%d\n",
392                         ATM_VERS_MAJ(ATM_VERSION), ATM_VERS_MIN(ATM_VERSION),
393                         ATM_VERS_MAJ(atm_version), ATM_VERS_MIN(atm_version));
394                 return (EINVAL);
395         }
396
397         /*
398          * Register ourselves as a network convergence module
399          */
400         err = atm_netconv_register(&ipatm_ncm);
401         if (err)
402                 goto done;
403
404         /*
405          * Register ourselves as an ATM endpoint
406          */
407         err = atm_endpoint_register(&ipatm_endpt);
408         if (err)
409                 goto done;
410
411         /*
412          * Get current system configuration
413          */
414         s = splnet();
415         for (pip = atm_interface_head; pip; pip = pip->pif_next) {
416                 /*
417                  * Process each network interface
418                  */
419                 for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
420                         struct ifnet    *ifp = (struct ifnet *)nip;
421                         struct in_ifaddr        *ia;
422
423                         /*
424                          * Attach interface
425                          */
426                         err = ipatm_nifstat(NCM_ATTACH, nip, 0);
427                         if (err) {
428                                 (void) splx(s);
429                                 goto done;
430                         }
431
432                         /*
433                          * If IP address has been set, register it
434                          */
435                         TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
436                                 if (ia->ia_ifp == ifp)
437                                         break;
438                         }
439                         if (ia) {
440                                 err = ipatm_nifstat(NCM_SETADDR, nip, (int)ia);
441                                 if (err) {
442                                         (void) splx(s);
443                                         goto done;
444                                 }
445                         }
446                 }
447         }
448         (void) splx(s);
449
450         /*
451          * Fill in union fields
452          */
453         ipatm_aal5llc.aal.v.aal5.forward_max_SDU_size =
454                 ATM_NIF_MTU + IPATM_LLC_LEN;
455         ipatm_aal5llc.aal.v.aal5.backward_max_SDU_size =
456                 ATM_NIF_MTU + IPATM_LLC_LEN;
457         ipatm_aal5llc.aal.v.aal5.SSCS_type = T_ATM_NULL;
458         ipatm_aal5llc.blli.v.layer_2_protocol.ID.simple_ID = T_ATM_BLLI2_I8802;
459
460         ipatm_aal5null.aal.v.aal5.forward_max_SDU_size = ATM_NIF_MTU;
461         ipatm_aal5null.aal.v.aal5.backward_max_SDU_size = ATM_NIF_MTU;
462         ipatm_aal5null.aal.v.aal5.SSCS_type = T_ATM_NULL;
463
464         ipatm_aal4null.aal.v.aal4.forward_max_SDU_size = ATM_NIF_MTU;
465         ipatm_aal4null.aal.v.aal4.backward_max_SDU_size = ATM_NIF_MTU;
466         ipatm_aal4null.aal.v.aal4.SSCS_type = T_ATM_NULL;
467         ipatm_aal4null.aal.v.aal4.mid_low = 0;
468         ipatm_aal4null.aal.v.aal4.mid_high = 1023;
469
470         /*
471          * Listen for incoming calls
472          */
473         for (i = 0;
474              i < (sizeof(ipatm_listeners) / sizeof(struct ipatm_listener));
475              i++) {
476                 struct attr_aal *aalp = &ipatm_listeners[i].attr.aal;
477                 int     maxsdu = ATM_NIF_MTU;
478
479                 /*
480                  * Fill in union fields
481                  */
482                 if (ipatm_listeners[i].attr.blli.tag_l2 == T_ATM_PRESENT) {
483                         struct t_atm_blli *bp = &ipatm_listeners[i].attr.blli.v;
484
485                         bp->layer_2_protocol.ID.simple_ID = T_ATM_BLLI2_I8802;
486                         maxsdu += IPATM_LLC_LEN;
487                 }
488                 if (aalp->type == ATM_AAL5) {
489                         aalp->v.aal5.forward_max_SDU_size = maxsdu;
490                         aalp->v.aal5.backward_max_SDU_size = maxsdu;
491                         aalp->v.aal5.SSCS_type = T_ATM_NULL;
492                 } else {
493                         aalp->v.aal4.forward_max_SDU_size = maxsdu;
494                         aalp->v.aal4.backward_max_SDU_size = maxsdu;
495                         aalp->v.aal4.SSCS_type = T_ATM_NULL;
496                         aalp->v.aal4.mid_low = 0;
497                         aalp->v.aal4.mid_high = 1023;
498                 }
499
500                 /*
501                  * Now start listening
502                  */
503                 if ((err = atm_cm_listen(&ipatm_endpt, (void *)i,
504                                 &ipatm_listeners[i].attr,
505                                 &ipatm_listeners[i].conn)) != 0)
506                         goto done;
507         }
508
509         /*
510          * Start background VCC idle timer
511          */
512         atm_timeout(&ipatm_itimer, IPATM_IDLE_TIME, ipatm_itimeout);
513
514 done:
515         return (err);
516 }
517
518
519 /*
520  * Halt ipatm processing 
521  * 
522  * This will be called just prior to unloading the module from
523  * memory.  All IP VCCs must be terminated before the protocol can 
524  * be shutdown.
525  *
526  * Arguments:
527  *      none
528  *
529  * Returns:
530  *      0       shutdown was successful 
531  *      errno   shutdown failed - reason indicated
532  *
533  */
534 static int
535 ipatm_stop()
536 {
537         struct ip_nif   *inp;
538         int     err = 0, i;
539         int     s = splnet();
540
541         /*
542          * Any VCCs still open??
543          */
544         if (ipatm_vccnt) {
545
546                 /* Yes, can't stop now */
547                 err = EBUSY;
548                 goto done;
549         }
550
551         /*
552          * Kill VCC idle timer
553          */
554         (void) atm_untimeout(&ipatm_itimer);
555
556         /*
557          * Stop listening for incoming calls
558          */
559         for (i = 0;
560              i < (sizeof(ipatm_listeners) / sizeof(struct ipatm_listener));
561              i++) {
562                 if (ipatm_listeners[i].conn != NULL) {
563                         (void) atm_cm_release(ipatm_listeners[i].conn,
564                                         &ipatm_cause);
565                 }
566         }
567
568         /*
569          * Detach all our interfaces
570          */
571         while ((inp = ipatm_nif_head) != NULL) {
572                 (void) ipatm_nifstat(NCM_DETACH, inp->inf_nif, 0);
573         }
574         
575         /*
576          * De-register from system
577          */
578         (void) atm_netconv_deregister(&ipatm_ncm);
579         (void) atm_endpoint_deregister(&ipatm_endpt);
580
581         /*
582          * Free up our storage pools
583          */
584         atm_release_pool(&ipatm_vcpool);
585         atm_release_pool(&ipatm_nifpool);
586
587 done:
588         (void) splx(s);
589         return (err);
590 }
591
592
593 #ifdef ATM_IP_MODULE 
594 /*
595  *******************************************************************
596  *
597  * Loadable Module Support
598  *
599  *******************************************************************
600  */
601 static int      ipatm_doload __P((void));
602 static int      ipatm_dounload __P((void));
603
604 /*
605  * Generic module load processing
606  * 
607  * This function is called by an OS-specific function when this
608  * module is being loaded.
609  *
610  * Arguments:
611  *      none
612  *
613  * Returns:
614  *      0       load was successful 
615  *      errno   load failed - reason indicated
616  *
617  */
618 static int
619 ipatm_doload()
620 {
621         int     err = 0;
622
623         /*
624          * Start us up
625          */
626         err = ipatm_start();
627         if (err)
628                 /* Problems, clean up */
629                 (void)ipatm_stop();
630
631         return (err);
632 }
633
634
635 /*
636  * Generic module unload processing
637  * 
638  * This function is called by an OS-specific function when this
639  * module is being unloaded.
640  *
641  * Arguments:
642  *      none
643  *
644  * Returns:
645  *      0       unload was successful 
646  *      errno   unload failed - reason indicated
647  *
648  */
649 static int
650 ipatm_dounload()
651 {
652         int     err = 0;
653
654         /*
655          * OK, try to clean up our mess
656          */
657         err = ipatm_stop();
658
659         return (err);
660 }
661
662
663 #ifdef sun
664 /*
665  * Loadable driver description
666  */
667 struct vdldrv ipatm_drv = {
668         VDMAGIC_PSEUDO, /* Pseudo Driver */
669         "ipatm_mod",    /* name */
670         NULL,           /* dev_ops */
671         NULL,           /* bdevsw */
672         NULL,           /* cdevsw */
673         0,              /* blockmajor */
674         0               /* charmajor */
675 };
676
677
678 /*
679  * Loadable module support entry point
680  * 
681  * This is the routine called by the vd driver for all loadable module
682  * functions for this pseudo driver.  This routine name must be specified
683  * on the modload(1) command.  This routine will be called whenever the
684  * modload(1), modunload(1) or modstat(1) commands are issued for this
685  * module.
686  *
687  * Arguments:
688  *      cmd     vd command code
689  *      vdp     pointer to vd driver's structure
690  *      vdi     pointer to command-specific vdioctl_* structure
691  *      vds     pointer to status structure (VDSTAT only)
692  *
693  * Returns:
694  *      0       command was successful 
695  *      errno   command failed - reason indicated
696  *
697  */
698 int
699 ipatm_mod(cmd, vdp, vdi, vds)
700         int             cmd;
701         struct vddrv    *vdp;
702         caddr_t         vdi;
703         struct vdstat   *vds;
704 {
705         int     err = 0;
706
707         switch (cmd) {
708
709         case VDLOAD:
710                 /*
711                  * Module Load
712                  *
713                  * We dont support any user configuration
714                  */
715                 err = ipatm_doload();
716                 if (err == 0)
717                         /* Let vd driver know about us */
718                         vdp->vdd_vdtab = (struct vdlinkage *)&ipatm_drv;
719                 break;
720
721         case VDUNLOAD:
722                 /*
723                  * Module Unload
724                  */
725                 err = ipatm_dounload();
726                 break;
727
728         case VDSTAT:
729                 /*
730                  * Module Status
731                  */
732
733                 /* Not much to say at the moment */
734
735                 break;
736
737         default:
738                 log(LOG_ERR, "ipatm_mod: Unknown vd command 0x%x\n", cmd);
739                 err = EINVAL;
740         }
741
742         return (err);
743 }
744 #endif  /* sun */
745
746 #ifdef __FreeBSD__
747
748 #include <sys/exec.h>
749 #include <sys/sysent.h>
750 #include <sys/lkm.h>
751
752 /*
753  * Loadable miscellaneous module description
754  */
755 MOD_MISC(ipatm);
756
757
758 /*
759  * Loadable module support "load" entry point
760  * 
761  * This is the routine called by the lkm driver whenever the
762  * modload(1) command is issued for this module.
763  *
764  * Arguments:
765  *      lkmtp   pointer to lkm drivers's structure
766  *      cmd     lkm command code
767  *
768  * Returns:
769  *      0       command was successful 
770  *      errno   command failed - reason indicated
771  *
772  */
773 static int
774 ipatm_load(lkmtp, cmd)
775         struct lkm_table        *lkmtp;
776         int             cmd;
777 {
778         return(ipatm_doload());
779 }
780
781
782 /*
783  * Loadable module support "unload" entry point
784  * 
785  * This is the routine called by the lkm driver whenever the
786  * modunload(1) command is issued for this module.
787  *
788  * Arguments:
789  *      lkmtp   pointer to lkm drivers's structure
790  *      cmd     lkm command code
791  *
792  * Returns:
793  *      0       command was successful 
794  *      errno   command failed - reason indicated
795  *
796  */
797 static int
798 ipatm_unload(lkmtp, cmd)
799         struct lkm_table        *lkmtp;
800         int             cmd;
801 {
802         return(ipatm_dounload());
803 }
804
805
806 /*
807  * Loadable module support entry point
808  * 
809  * This is the routine called by the lkm driver for all loadable module
810  * functions for this driver.  This routine name must be specified
811  * on the modload(1) command.  This routine will be called whenever the
812  * modload(1), modunload(1) or modstat(1) commands are issued for this
813  * module.
814  *
815  * Arguments:
816  *      lkmtp   pointer to lkm drivers's structure
817  *      cmd     lkm command code
818  *      ver     lkm version
819  *
820  * Returns:
821  *      0       command was successful 
822  *      errno   command failed - reason indicated
823  *
824  */
825 int
826 ipatm_mod(lkmtp, cmd, ver)
827         struct lkm_table        *lkmtp;
828         int             cmd;
829         int             ver;
830 {
831         MOD_DISPATCH(ipatm, lkmtp, cmd, ver,
832                 ipatm_load, ipatm_unload, lkm_nullcmd);
833 }
834 #endif  /* __FreeBSD__ */
835
836 #else   /* !ATM_IP_MODULE */
837
838 /*
839  *******************************************************************
840  *
841  * Kernel Compiled Module Support
842  *
843  *******************************************************************
844  */
845 static void     ipatm_doload __P((void *));
846
847 SYSINIT(atmipatm, SI_SUB_PROTO_END, SI_ORDER_ANY, ipatm_doload, NULL)
848
849 /*
850  * Kernel initialization
851  * 
852  * Arguments:
853  *      arg     Not used
854  *
855  * Returns:
856  *      none
857  *
858  */
859 static void
860 ipatm_doload(void *arg)
861 {
862         int     err = 0;
863
864         /*
865          * Start us up
866          */
867         err = ipatm_start();
868         if (err) {
869                 /* Problems, clean up */
870                 (void)ipatm_stop();
871
872                 log(LOG_ERR, "IP over ATM unable to initialize (%d)!!\n", err);
873         }
874         return;
875 }
876 #endif  /* ATM_IP_MODULE */
877