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