int natm_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, struct mbuf *control, struct proc *p) { int error = 0, s, s2; struct natmpcb *npcb; struct sockaddr_natm *snatm; struct atm_pseudoioctl api; struct atm_pseudohdr *aph; struct atm_rawioctl ario; struct ifnet *ifp; int proto = so->so_proto->pr_protocol; s = splsoftnet(); npcb = (struct natmpcb *) so->so_pcb; if (npcb == NULL && req != PRU_ATTACH) { error = EINVAL; goto done; } switch (req) { case PRU_ATTACH: /* attach protocol to up */ if (npcb) { error = EISCONN; break; } if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { if (proto == PROTO_NATMAAL5) error = soreserve(so, natm5_sendspace, natm5_recvspace); else error = soreserve(so, natm0_sendspace, natm0_recvspace); if (error) break; } so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK)); npcb->npcb_socket = so; break; case PRU_DETACH: /* detach protocol from up */ /* * we turn on 'drain' *before* we sofree. */ npcb_free(npcb, NPCB_DESTROY); /* drain */ so->so_pcb = NULL; sofree(so); break; case PRU_CONNECT: /* establish connection to peer */ /* * validate nam and npcb */ if (nam->m_len != sizeof(*snatm)) { error = EINVAL; break; } snatm = mtod(nam, struct sockaddr_natm *); if (snatm->snatm_len != sizeof(*snatm) || (npcb->npcb_flags & NPCB_FREE) == 0) { error = EINVAL; break; } if (snatm->snatm_family != AF_NATM) { error = EAFNOSUPPORT; break; } snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination since ifunit() uses strcmp */ /* * convert interface string to ifp, validate. */ ifp = ifunit(snatm->snatm_if); if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) { error = ENXIO; break; } if (ifp->if_output != atm_output) { error = EAFNOSUPPORT; break; } /* * register us with the NATM PCB layer */ if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) { error = EADDRINUSE; break; } /* * enable rx */ ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0; ATM_PH_VPI(&api.aph) = npcb->npcb_vpi; ATM_PH_SETVCI(&api.aph, npcb->npcb_vci); api.rxhand = npcb; s2 = splnet(); if (ifp->if_ioctl == NULL || ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) { splx(s2); npcb_free(npcb, NPCB_REMOVE); error = EIO; break; } splx(s2); soisconnected(so); break; case PRU_DISCONNECT: /* disconnect from peer */ if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) { printf("natm: disconnected check\n"); error = EIO; break; } ifp = npcb->npcb_ifp; /* * disable rx */ ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5; ATM_PH_VPI(&api.aph) = npcb->npcb_vpi; ATM_PH_SETVCI(&api.aph, npcb->npcb_vci); api.rxhand = npcb; s2 = splnet(); if (ifp->if_ioctl != NULL) ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api); splx(s2); npcb_free(npcb, NPCB_REMOVE); soisdisconnected(so); break; case PRU_SHUTDOWN: /* won't send any more data */ socantsendmore(so); break; case PRU_SEND: /* send this data */ if (control && control->m_len) { m_freem(control); m_freem(m); error = EINVAL; break; } /* * send the data. we must put an atm_pseudohdr on first */ M_PREPEND(m, sizeof(*aph), M_WAITOK); aph = mtod(m, struct atm_pseudohdr *); ATM_PH_VPI(aph) = npcb->npcb_vpi; ATM_PH_SETVCI(aph, npcb->npcb_vci); ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0; error = atm_output(npcb->npcb_ifp, m, NULL, NULL); break; case PRU_SENSE: /* return status into m */ /* return zero? */ break; case PRU_PEERADDR: /* fetch peer's address */ snatm = mtod(nam, struct sockaddr_natm *); bzero(snatm, sizeof(*snatm)); nam->m_len = snatm->snatm_len = sizeof(*snatm); snatm->snatm_family = AF_NATM; #if defined(__NetBSD__) || defined(__OpenBSD__) bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if)); #elif defined(__FreeBSD__) sprintf(snatm->snatm_if, "%s%d", npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit); #endif snatm->snatm_vci = npcb->npcb_vci; snatm->snatm_vpi = npcb->npcb_vpi; break; case PRU_CONTROL: /* control operations on protocol */ /* * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to * SIOCXRAWATM and pass it to the driver. */ if ((u_long)m == SIOCRAWATM) { if (npcb->npcb_ifp == NULL) { error = ENOTCONN; break; } ario.npcb = npcb; ario.rawvalue = *((int *)nam); error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, SIOCXRAWATM, (caddr_t) &ario); if (!error) { if (ario.rawvalue) npcb->npcb_flags |= NPCB_RAW; else npcb->npcb_flags &= ~(NPCB_RAW); } break; } error = EOPNOTSUPP; break; case PRU_BIND: /* bind socket to address */ case PRU_LISTEN: /* listen for connection */ case PRU_ACCEPT: /* accept connection from peer */ case PRU_CONNECT2: /* connect two sockets */ case PRU_ABORT: /* abort (fast DISCONNECT, DETACH) */ /* (only happens if LISTEN socket) */ case PRU_RCVD: /* have taken data; more room now */ case PRU_FASTTIMO: /* 200ms timeout */ case PRU_SLOWTIMO: /* 500ms timeout */ case PRU_RCVOOB: /* retrieve out of band data */ case PRU_SENDOOB: /* send out of band data */ case PRU_PROTORCV: /* receive from below */ case PRU_PROTOSEND: /* send to below */ case PRU_SOCKADDR: /* fetch socket's address */ #ifdef DIAGNOSTIC printf("natm: PRU #%d unsupported\n", req); #endif error = EOPNOTSUPP; break; default: panic("natm usrreq"); } done: splx(s); return(error); }
/* * atm_rtrequest: handle ATM rt request (in support of generic code) * inputs: "req" = request code * "rt" = route entry * "info" = rt_addrinfo */ void atm_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) { struct sockaddr *gate = rt->rt_gateway; struct atmio_openvcc op; struct atmio_closevcc cl; u_char *addr; u_int alen; #ifdef NATM struct sockaddr_in *sin; struct natmpcb *npcb = NULL; #endif static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; if (rt->rt_flags & RTF_GATEWAY) /* link level requests only */ return; switch (req) { case RTM_RESOLVE: /* resolve: only happens when cloning */ printf("atm_rtrequest: RTM_RESOLVE request detected?\n"); break; case RTM_ADD: /* * route added by a command (e.g. ifconfig, route, arp...). * * first check to see if this is not a host route, in which * case we are being called via "ifconfig" to set the address. */ if ((rt->rt_flags & RTF_HOST) == 0) { rt_setgate(rt,rt_key(rt),(struct sockaddr *)&null_sdl); gate = rt->rt_gateway; SDL(gate)->sdl_type = rt->rt_ifp->if_type; SDL(gate)->sdl_index = rt->rt_ifp->if_index; break; } if (gate->sa_family != AF_LINK || gate->sa_len < sizeof(null_sdl)) { log(LOG_DEBUG, "atm_rtrequest: bad gateway value"); break; } KASSERT(rt->rt_ifp->if_ioctl != NULL, ("atm_rtrequest: null ioctl")); /* * Parse and verify the link level address as * an open request */ #ifdef NATM NATM_LOCK(); #endif bzero(&op, sizeof(op)); addr = LLADDR(SDL(gate)); alen = SDL(gate)->sdl_alen; if (alen < 4) { printf("%s: bad link-level address\n", __func__); goto failed; } if (alen == 4) { /* old type address */ GET1BYTE(op.param.flags, addr, alen); GET1BYTE(op.param.vpi, addr, alen); GET2BYTE(op.param.vci, addr, alen); op.param.traffic = ATMIO_TRAFFIC_UBR; op.param.aal = (op.param.flags & ATM_PH_AAL5) ? ATMIO_AAL_5 : ATMIO_AAL_0; } else { /* new address */ op.param.aal = ATMIO_AAL_5; GET1BYTE(op.param.flags, addr, alen); op.param.flags &= ATM_PH_LLCSNAP; GET1BYTE(op.param.vpi, addr, alen); GET2BYTE(op.param.vci, addr, alen); GET1BYTE(op.param.traffic, addr, alen); switch (op.param.traffic) { case ATMIO_TRAFFIC_UBR: if (alen >= 3) GET3BYTE(op.param.tparam.pcr, addr, alen); break; case ATMIO_TRAFFIC_CBR: if (alen < 3) goto bad_param; GET3BYTE(op.param.tparam.pcr, addr, alen); break; case ATMIO_TRAFFIC_VBR: if (alen < 3 * 3) goto bad_param; GET3BYTE(op.param.tparam.pcr, addr, alen); GET3BYTE(op.param.tparam.scr, addr, alen); GET3BYTE(op.param.tparam.mbs, addr, alen); break; case ATMIO_TRAFFIC_ABR: if (alen < 4 * 3 + 2 + 1 * 2 + 3) goto bad_param; GET3BYTE(op.param.tparam.pcr, addr, alen); GET3BYTE(op.param.tparam.mcr, addr, alen); GET3BYTE(op.param.tparam.icr, addr, alen); GET3BYTE(op.param.tparam.tbe, addr, alen); GET1BYTE(op.param.tparam.nrm, addr, alen); GET1BYTE(op.param.tparam.trm, addr, alen); GET2BYTE(op.param.tparam.adtf, addr, alen); GET1BYTE(op.param.tparam.rif, addr, alen); GET1BYTE(op.param.tparam.rdf, addr, alen); GET1BYTE(op.param.tparam.cdf, addr, alen); break; default: bad_param: printf("%s: bad traffic params\n", __func__); goto failed; } } op.param.rmtu = op.param.tmtu = rt->rt_ifp->if_mtu; #ifdef NATM /* * let native ATM know we are using this VCI/VPI * (i.e. reserve it) */ sin = (struct sockaddr_in *) rt_key(rt); if (sin->sin_family != AF_INET) goto failed; npcb = npcb_add(NULL, rt->rt_ifp, op.param.vci, op.param.vpi); if (npcb == NULL) goto failed; npcb->npcb_flags |= NPCB_IP; npcb->ipaddr.s_addr = sin->sin_addr.s_addr; /* XXX: move npcb to llinfo when ATM ARP is ready */ rt->rt_llinfo = (caddr_t) npcb; rt->rt_flags |= RTF_LLINFO; #endif /* * let the lower level know this circuit is active */ op.rxhand = NULL; op.param.flags |= ATMIO_FLAG_ASYNC; if (rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMOPENVCC, (caddr_t)&op) != 0) { printf("atm: couldn't add VC\n"); goto failed; } SDL(gate)->sdl_type = rt->rt_ifp->if_type; SDL(gate)->sdl_index = rt->rt_ifp->if_index; #ifdef NATM NATM_UNLOCK(); #endif break; failed: #ifdef NATM if (npcb) { npcb_free(npcb, NPCB_DESTROY); rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; } NATM_UNLOCK(); #endif /* mark as invalid. We cannot RTM_DELETE the route from * here, because the recursive call to rtrequest1 does * not really work. */ rt->rt_flags |= RTF_REJECT; break; case RTM_DELETE: #ifdef NATM /* * tell native ATM we are done with this VC */ if (rt->rt_flags & RTF_LLINFO) { NATM_LOCK(); npcb_free((struct natmpcb *)rt->rt_llinfo, NPCB_DESTROY); rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; NATM_UNLOCK(); } #endif /* * tell the lower layer to disable this circuit */ bzero(&op, sizeof(op)); addr = LLADDR(SDL(gate)); addr++; cl.vpi = *addr++; cl.vci = *addr++ << 8; cl.vci |= *addr++; (void)rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMCLOSEVCC, (caddr_t)&cl); break; } }
void atm_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) { struct sockaddr *gate = rt->rt_gateway; struct atm_pseudoioctl api; #ifdef NATM const struct sockaddr_in *sin; struct natmpcb *npcb = NULL; const struct atm_pseudohdr *aph; #endif const struct ifnet *ifp = rt->rt_ifp; uint8_t namelen = strlen(ifp->if_xname); uint8_t addrlen = ifp->if_addrlen; if (rt->rt_flags & RTF_GATEWAY) /* link level requests only */ return; switch (req) { case RTM_RESOLVE: /* resolve: only happens when cloning */ printf("atm_rtrequest: RTM_RESOLVE request detected?\n"); break; case RTM_ADD: /* * route added by a command (e.g. ifconfig, route, arp...). * * first check to see if this is not a host route, in which * case we are being called via "ifconfig" to set the address. */ if ((rt->rt_flags & RTF_HOST) == 0) { union { struct sockaddr sa; struct sockaddr_dl sdl; struct sockaddr_storage ss; } u; sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type, NULL, namelen, NULL, addrlen); rt_setgate(rt, &u.sa); gate = rt->rt_gateway; break; } if ((rt->rt_flags & RTF_CLONING) != 0) { printf("atm_rtrequest: cloning route detected?\n"); break; } if (gate->sa_family != AF_LINK || gate->sa_len < sockaddr_dl_measure(namelen, addrlen)) { log(LOG_DEBUG, "atm_rtrequest: bad gateway value\n"); break; } #ifdef DIAGNOSTIC if (rt->rt_ifp->if_ioctl == NULL) panic("atm null ioctl"); #endif #ifdef NATM /* * let native ATM know we are using this VCI/VPI * (i.e. reserve it) */ sin = satocsin(rt_getkey(rt)); if (sin->sin_family != AF_INET) goto failed; aph = (const struct atm_pseudohdr *)CLLADDR(satosdl(gate)); npcb = npcb_add(NULL, rt->rt_ifp, ATM_PH_VCI(aph), ATM_PH_VPI(aph)); if (npcb == NULL) goto failed; npcb->npcb_flags |= NPCB_IP; npcb->ipaddr.s_addr = sin->sin_addr.s_addr; /* XXX: move npcb to llinfo when ATM ARP is ready */ rt->rt_llinfo = (void *) npcb; rt->rt_flags |= RTF_LLINFO; #endif /* * let the lower level know this circuit is active */ memcpy(&api.aph, CLLADDR(satocsdl(gate)), sizeof(api.aph)); api.rxhand = NULL; if (rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMENA, &api) != 0) { printf("atm: couldn't add VC\n"); goto failed; } satosdl(gate)->sdl_type = rt->rt_ifp->if_type; satosdl(gate)->sdl_index = rt->rt_ifp->if_index; break; failed: #ifdef NATM if (npcb) { npcb_free(npcb, NPCB_DESTROY); rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; } #endif rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL); break; case RTM_DELETE: #ifdef NATM /* * tell native ATM we are done with this VC */ if (rt->rt_flags & RTF_LLINFO) { npcb_free((struct natmpcb *)rt->rt_llinfo, NPCB_DESTROY); rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; } #endif /* * tell the lower layer to disable this circuit */ memcpy(&api.aph, CLLADDR(satocsdl(gate)), sizeof(api.aph)); api.rxhand = NULL; (void)rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMDIS, &api); break; } }
static int natm_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *p) { struct natmpcb *npcb; struct sockaddr_natm *snatm; struct atmio_openvcc op; struct ifnet *ifp; int error = 0; int proto = so->so_proto->pr_protocol; npcb = (struct natmpcb *)so->so_pcb; KASSERT(npcb != NULL, ("natm_usr_connect: npcb == NULL")); /* * Validate nam and npcb. */ NATM_LOCK(); snatm = (struct sockaddr_natm *)nam; if (snatm->snatm_len != sizeof(*snatm) || (npcb->npcb_flags & NPCB_FREE) == 0) { NATM_UNLOCK(); return (EINVAL); } if (snatm->snatm_family != AF_NATM) { NATM_UNLOCK(); return (EAFNOSUPPORT); } snatm->snatm_if[IFNAMSIZ - 1] = '\0'; /* XXX ensure null termination since ifunit() uses strcmp */ /* * Convert interface string to ifp, validate. */ ifp = ifunit(snatm->snatm_if); if (ifp == NULL || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { NATM_UNLOCK(); return (ENXIO); } if (ifp->if_output != atm_output) { NATM_UNLOCK(); return (EAFNOSUPPORT); } /* * Register us with the NATM PCB layer. */ if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) { NATM_UNLOCK(); return (EADDRINUSE); } /* * Open the channel. * * XXXRW: Eventually desirable to hold mutex over ioctl? */ bzero(&op, sizeof(op)); op.rxhand = npcb; op.param.flags = ATMIO_FLAG_PVC; op.param.vpi = npcb->npcb_vpi; op.param.vci = npcb->npcb_vci; op.param.rmtu = op.param.tmtu = ifp->if_mtu; op.param.aal = (proto == PROTO_NATMAAL5) ? ATMIO_AAL_5 : ATMIO_AAL_0; op.param.traffic = ATMIO_TRAFFIC_UBR; NATM_UNLOCK(); if (ifp->if_ioctl == NULL || ifp->if_ioctl(ifp, SIOCATMOPENVCC, (caddr_t)&op) != 0) return (EIO); soisconnected(so); return (error); }
static int natm_usr_connect(struct socket *so, struct mbuf *nam) { struct natmpcb *npcb; struct sockaddr_natm *snatm; struct atm_pseudoioctl api; struct atm_pseudohdr *aph; struct ifnet *ifp; int error = 0; int s2, s = SPLSOFTNET(); int proto = so->so_proto->pr_protocol; npcb = (struct natmpcb *) so->so_pcb; if (npcb == NULL) { error = EINVAL; goto out; } /* * validate nam and npcb */ if (nam->m_len != sizeof(*snatm)) { error = EINVAL; goto out; } snatm = mtod(nam, struct sockaddr_natm *); if (snatm->snatm_len != sizeof(*snatm) || (npcb->npcb_flags & NPCB_FREE) == 0) { error = EINVAL; goto out; } if (snatm->snatm_family != AF_NATM) { error = EAFNOSUPPORT; goto out; } snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination since ifunit() uses strcmp */ /* * convert interface string to ifp, validate. */ ifp = ifunit(snatm->snatm_if); if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) { error = ENXIO; goto out; } if (ifp->if_output != atm_output) { error = EAFNOSUPPORT; goto out; } /* * register us with the NATM PCB layer */ if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) { error = EADDRINUSE; goto out; } /* * enable rx */ ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0; ATM_PH_VPI(&api.aph) = npcb->npcb_vpi; ATM_PH_SETVCI(&api.aph, npcb->npcb_vci); api.rxhand = npcb; s2 = splimp(); if (ifp->if_ioctl == NULL || ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) { splx(s2); npcb_free(npcb, NPCB_REMOVE); error = EIO; goto out; } splx(s2); soisconnected(so); out: splx(s); return (error); }
/* * atm_rtrequest: handle ATM rt request (in support of generic code) * inputs: "req" = request code * "rt" = route entry * "info" = rt_addrinfo */ void atm_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) { struct sockaddr *gate = rt->rt_gateway; struct atm_pseudoioctl api; #ifdef NATM struct sockaddr_in *sin; struct natmpcb *npcb = NULL; struct atm_pseudohdr *aph; #endif static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; int error; if (rt->rt_flags & RTF_GATEWAY) /* link level requests only */ return; switch (req) { case RTM_RESOLVE: /* resolve: only happens when cloning */ kprintf("atm_rtrequest: RTM_RESOLVE request detected?\n"); break; case RTM_ADD: /* * route added by a command (e.g. ifconfig, route, arp...). * * first check to see if this is not a host route, in which * case we are being called via "ifconfig" to set the address. */ if ((rt->rt_flags & RTF_HOST) == 0) { rt_setgate(rt,rt_key(rt),(struct sockaddr *)&null_sdl, RTL_DONTREPORT); gate = rt->rt_gateway; SDL(gate)->sdl_type = rt->rt_ifp->if_type; SDL(gate)->sdl_index = rt->rt_ifp->if_index; break; } if ((rt->rt_flags & RTF_CLONING) != 0) { kprintf("atm_rtrequest: cloning route detected?\n"); break; } if (gate->sa_family != AF_LINK || gate->sa_len < sizeof(null_sdl)) { log(LOG_DEBUG, "atm_rtrequest: bad gateway value"); break; } #ifdef DIAGNOSTIC if (rt->rt_ifp->if_ioctl == NULL) panic("atm null ioctl"); #endif #ifdef NATM /* * let native ATM know we are using this VCI/VPI * (i.e. reserve it) */ sin = (struct sockaddr_in *) rt_key(rt); if (sin->sin_family != AF_INET) goto failed; aph = (struct atm_pseudohdr *) LLADDR(SDL(gate)); npcb = npcb_add(NULL, rt->rt_ifp, ATM_PH_VCI(aph), ATM_PH_VPI(aph)); if (npcb == NULL) goto failed; npcb->npcb_flags |= NPCB_IP; npcb->ipaddr.s_addr = sin->sin_addr.s_addr; /* XXX: move npcb to llinfo when ATM ARP is ready */ rt->rt_llinfo = npcb; rt->rt_flags |= RTF_LLINFO; #endif /* * let the lower level know this circuit is active */ bcopy(LLADDR(SDL(gate)), &api.aph, sizeof(api.aph)); api.rxhand = NULL; ifnet_serialize_all(rt->rt_ifp); error = rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMENA, (caddr_t)&api, NULL); ifnet_deserialize_all(rt->rt_ifp); if (error) { kprintf("atm: couldn't add VC\n"); goto failed; } SDL(gate)->sdl_type = rt->rt_ifp->if_type; SDL(gate)->sdl_index = rt->rt_ifp->if_index; break; failed: #ifdef NATM if (npcb) { npcb_free(npcb, NPCB_DESTROY); rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; } #endif rtrequest(RTM_DELETE, rt_key(rt), NULL, rt_mask(rt), 0, NULL); break; case RTM_DELETE: #ifdef NATM /* * tell native ATM we are done with this VC */ if (rt->rt_flags & RTF_LLINFO) { npcb_free(rt->rt_llinfo, NPCB_DESTROY); rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; } #endif /* * tell the lower layer to disable this circuit */ bcopy(LLADDR(SDL(gate)), &api.aph, sizeof(api.aph)); api.rxhand = NULL; ifnet_serialize_all(rt->rt_ifp); rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMDIS, (caddr_t)&api, NULL); ifnet_deserialize_all(rt->rt_ifp); break; } }