diff options
Diffstat (limited to 'sys/netatm/atm_if.c')
-rw-r--r-- | sys/netatm/atm_if.c | 1202 |
1 files changed, 1202 insertions, 0 deletions
diff --git a/sys/netatm/atm_if.c b/sys/netatm/atm_if.c new file mode 100644 index 0000000..a07ccc2 --- /dev/null +++ b/sys/netatm/atm_if.c @@ -0,0 +1,1202 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: atm_if.c,v 1.13 1998/07/23 21:43:55 root Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM interface management + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_if.c,v 1.13 1998/07/23 21:43:55 root Exp $"; +#endif + +#include <netatm/kern_include.h> + + +#if (defined(BSD) && (BSD < 199506)) +extern int ifqmaxlen; +#endif + +/* + * Local functions + */ +static int atm_physif_ioctl __P((int, caddr_t, caddr_t)); +#if (defined(BSD) && (BSD >= 199306)) +static int atm_netif_rtdel __P((struct radix_node *, void *)); +#endif +static int atm_if_ioctl __P((struct ifnet *, u_long, caddr_t)); +static int atm_ifparse __P((char *, char *, int, int *)); + +/* + * Local variables + */ +static int (*atm_ifouttbl[AF_MAX+1]) + __P((struct ifnet *, KBuffer *, struct sockaddr *)) + = {NULL}; + + +/* + * Register an ATM physical interface + * + * Each ATM device interface must register itself here upon completing + * its internal initialization. This applies to both linked and loaded + * device drivers. The interface must be registered before a signalling + * manager can be attached. + * + * Arguments: + * cup pointer to interface's common unit structure + * name pointer to device name string + * sdp pointer to interface's stack services + * + * Returns: + * 0 registration successful + * errno registration failed - reason indicated + * + */ +int +atm_physif_register(cup, name, sdp) + Cmn_unit *cup; + char *name; + struct stack_defn *sdp; +{ + struct atm_pif *pip; + int s; + + /* + * See if we need to be initialized + */ + if (!atm_init) + atm_initialize(); + + /* + * Make sure we're not already registered + */ + if (cup->cu_flags & CUF_REGISTER) { + return (EALREADY); + } + + s = splnet(); + + /* + * Make sure an interface is only registered once + */ + for (pip = atm_interface_head; pip != NULL; pip = pip->pif_next) { + if ((cup->cu_unit == pip->pif_unit) && + (strcmp(name, pip->pif_name) == 0)) { + (void) splx(s); + return (EEXIST); + } + } + + /* + * Fill in physical interface parameters + */ + pip = &cup->cu_pif; + pip->pif_name = name; + pip->pif_unit = cup->cu_unit; + pip->pif_flags = PIF_UP; + pip->pif_services = sdp; + pip->pif_ioctl = atm_physif_ioctl; + + /* + * Link in the interface and mark us registered + */ + LINK2TAIL(pip, struct atm_pif, atm_interface_head, pif_next); + cup->cu_flags |= CUF_REGISTER; + + (void) splx(s); + return (0); +} + + +/* + * De-register an ATM physical interface + * + * Each ATM interface must de-register itself before downing the interface. + * The interface's signalling manager will be detached and any network + * interface and VCC control blocks will be freed. + * + * Arguments: + * cup pointer to interface's common unit structure + * + * Returns: + * 0 de-registration successful + * errno de-registration failed - reason indicated + * + */ +int +atm_physif_deregister(cup) + Cmn_unit *cup; +{ + struct atm_pif *pip = (struct atm_pif *)&cup->cu_pif; + Cmn_vcc *cvp; + int err; + int s = splnet(); + + /* + * Detach and deregister, if needed + */ + if ((cup->cu_flags & CUF_REGISTER)) { + + /* + * Detach from signalling manager + */ + if (pip->pif_sigmgr != NULL) { + err = atm_sigmgr_detach(pip); + if (err && (err != ENOENT)) { + (void) splx(s); + return (err); + } + } + + /* + * Make sure signalling manager is detached + */ + if (pip->pif_sigmgr != NULL) { + (void) splx(s); + return (EBUSY); + } + + /* + * Unlink interface + */ + UNLINK(pip, struct atm_pif, atm_interface_head, pif_next); + + cup->cu_flags &= ~CUF_REGISTER; + } + + /* + * Free all of our network interfaces + */ + atm_physif_freenifs(pip); + + /* + * Free unit's vcc information + */ + cvp = cup->cu_vcc; + while (cvp) { + atm_free(cvp); + cvp = cvp->cv_next; + } + cup->cu_vcc = (Cmn_vcc *)NULL; + + (void) splx(s); + + return (0); +} + + +/* + * Free all network interfaces on a physical interface + * + * Arguments + * pip pointer to physical interface structure + * + * Returns + * none + * + */ +void +atm_physif_freenifs(pip) + struct atm_pif *pip; +{ + struct atm_nif *nip = pip->pif_nif; + int s = splnet(); + + while ( nip ) + { + /* + * atm_nif_detach zeros pointers - save so we can + * walk the chain. + */ + struct atm_nif *nipp = nip->nif_pnext; + + /* + * Clean up network i/f trails + */ + atm_nif_detach ( nip ); + atm_free ((caddr_t)nip); + nip = nipp; + } + pip->pif_nif = (struct atm_nif *)NULL; + + (void) splx(s); + + return; +} + + +/* + * Handle physical interface ioctl's + * + * See <netatm/atm_ioctl.h> for definitions. + * + * Called at splnet. + * + * Arguments: + * code Ioctl function (sub)code + * data Data block. On input contains command, + * on output, contains results + * arg Optional code specific arguments + * + * Returns: + * 0 Request processed successfully + * errno Request failed - reason code + * + */ +static int +atm_physif_ioctl(code, data, arg) + int code; + caddr_t data; + caddr_t arg; +{ + struct atminfreq *aip = (struct atminfreq *)data; + struct atmsetreq *asr = (struct atmsetreq *)data; + struct atm_pif *pip; + struct atm_nif *nip; + struct sigmgr *smp; + struct siginst *sip; + struct ifnet *ifp; + Cmn_unit *cup; + Atm_config *acp; + caddr_t buf = aip->air_buf_addr; + struct air_phy_stat_rsp *apsp; + struct air_int_rsp apr; + struct air_netif_rsp anr; + struct air_cfg_rsp acr; + int count, len, buf_len = aip->air_buf_len; + int err = 0; + char ifname[2*IFNAMSIZ]; +#if (defined(BSD) && (BSD >= 199103)) + struct ifaddr *ifa; + struct in_ifaddr *ia; + struct sockaddr_dl *sdl; +#endif + + + switch ( aip->air_opcode ) { + + case AIOCS_INF_INT: + /* + * Get physical interface information + */ + aip = (struct atminfreq *)data; + pip = (struct atm_pif *)arg; + + /* + * Make sure there's room in user buffer + */ + if (aip->air_buf_len < sizeof(apr)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + KM_ZERO((caddr_t)&apr, sizeof(apr)); + smp = pip->pif_sigmgr; + sip = pip->pif_siginst; + (void) sprintf(apr.anp_intf, "%s%d", pip->pif_name, + pip->pif_unit ); + if ( pip->pif_nif ) + { + strcpy(apr.anp_nif_pref, pip->pif_nif->nif_if.if_name); + + nip = pip->pif_nif; + while ( nip ) { + apr.anp_nif_cnt++; + nip = nip->nif_pnext; + } + } + if (sip) { + ATM_ADDR_COPY(&sip->si_addr, &apr.anp_addr); + ATM_ADDR_COPY(&sip->si_subaddr, &apr.anp_subaddr); + apr.anp_sig_proto = smp->sm_proto; + apr.anp_sig_state = sip->si_state; + } + + /* + * Copy data to user buffer + */ + err = copyout((caddr_t)&apr, aip->air_buf_addr, sizeof(apr)); + if (err) + break; + + /* + * Update buffer pointer/count + */ + aip->air_buf_addr += sizeof(apr); + aip->air_buf_len -= sizeof(apr); + break; + + case AIOCS_INF_NIF: + /* + * Get network interface information + */ + aip = (struct atminfreq *)data; + nip = (struct atm_nif *)arg; + ifp = &nip->nif_if; + pip = nip->nif_pif; + + /* + * Make sure there's room in user buffer + */ + if (aip->air_buf_len < sizeof(anr)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + KM_ZERO((caddr_t)&anr, sizeof(anr)); + (void) sprintf(anr.anp_intf, "%s%d", ifp->if_name, + ifp->if_unit); + IFP_TO_IA(ifp, ia); + if (ia) { + anr.anp_proto_addr = *ia->ia_ifa.ifa_addr; + } + (void) sprintf(anr.anp_phy_intf, "%s%d", pip->pif_name, + pip->pif_unit); + + /* + * Copy data to user buffer + */ + err = copyout((caddr_t)&anr, aip->air_buf_addr, sizeof(anr)); + if (err) + break; + + /* + * Update buffer pointer/count + */ + aip->air_buf_addr += sizeof(anr); + aip->air_buf_len -= sizeof(anr); + break; + + case AIOCS_INF_PIS: + /* + * Get per interface statistics + */ + pip = (struct atm_pif *)arg; + if ( pip == NULL ) + return ( ENXIO ); + sprintf ( ifname, "%s%d", pip->pif_name, pip->pif_unit ); + + /* + * Cast response into users buffer + */ + apsp = (struct air_phy_stat_rsp *)buf; + + /* + * Sanity check + */ + len = sizeof ( struct air_phy_stat_rsp ); + if ( buf_len < len ) + return ( ENOSPC ); + + /* + * Copy interface name into response + */ + if ( err = copyout ( ifname, apsp->app_intf, IFNAMSIZ ) ) + break; + + /* + * Copy counters + */ + if ( err = copyout ( &pip->pif_ipdus, &apsp->app_ipdus, + len - sizeof ( apsp->app_intf ) ) ) + break; + + /* + * Adjust buffer elements + */ + buf += len; + buf_len -= len; + + aip->air_buf_addr = buf; + aip->air_buf_len = buf_len; + break; + + case AIOCS_SET_NIF: + /* + * Set NIF - allow user to configure 1 or more logical + * interfaces per physical interface. + */ + + /* + * Get pointer to physical interface structure from + * ioctl argument. + */ + pip = (struct atm_pif *)arg; + cup = (Cmn_unit *)pip; + + /* + * Sanity check - are we already connected to something? + */ + if ( pip->pif_sigmgr ) + { + err = EBUSY; + break; + } + + /* + * Free any previously allocated NIFs + */ + atm_physif_freenifs(pip); + + /* + * Add list of interfaces + */ + for ( count = 0; count < asr->asr_nif_cnt; count++ ) + { + nip = (struct atm_nif *)atm_allocate(cup->cu_nif_pool); + if ( nip == NULL ) + { + /* + * Destroy any successful nifs + */ + atm_physif_freenifs(pip); + err = ENOMEM; + break; + } + + nip->nif_pif = pip; + ifp = &nip->nif_if; + + strcpy ( nip->nif_name, asr->asr_nif_pref ); + nip->nif_sel = count; + + ifp->if_name = nip->nif_name; + ifp->if_unit = count; + ifp->if_mtu = ATM_NIF_MTU; + ifp->if_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING; + ifp->if_output = atm_ifoutput; + ifp->if_ioctl = atm_if_ioctl; + ifp->if_snd.ifq_maxlen = ifqmaxlen; +#if (defined(BSD) && (BSD >= 199103)) + /* + * Set if_type and if_baudrate + */ + ifp->if_type = IFT_ATM; + switch ( cup->cu_config.ac_media ) { + case MEDIA_TAXI_100: + ifp->if_baudrate = 100000000; + break; + case MEDIA_TAXI_140: + ifp->if_baudrate = 140000000; + break; + case MEDIA_OC3C: + case MEDIA_OC12C: + case MEDIA_UTP155: + ifp->if_baudrate = 155000000; + break; + } +#endif + + if ( err = atm_nif_attach ( nip ) ) + { + atm_free ( (caddr_t)nip ); + + /* + * Destroy any successful nifs + */ + atm_physif_freenifs(pip); + break; + } +#if (defined(BSD) && (BSD >= 199103)) + /* + * Set macaddr in <Link> address + */ + ifp->if_addrlen = 6; + ifa = ifnet_addrs[ifp->if_index - 1]; + if ( ifa ) { + sdl = (struct sockaddr_dl *) + ifa->ifa_addr; + sdl->sdl_type = IFT_ETHER; + sdl->sdl_alen = ifp->if_addrlen; + bcopy ( (caddr_t)&cup->cu_config.ac_macaddr, + LLADDR(sdl), ifp->if_addrlen ); + } +#endif + } + break; + + case AIOCS_INF_CFG: + /* + * Get adapter configuration information + */ + aip = (struct atminfreq *)data; + pip = (struct atm_pif *)arg; + cup = (Cmn_unit *)pip; + acp = &cup->cu_config; + + /* + * Make sure there's room in user buffer + */ + if (aip->air_buf_len < sizeof(acr)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + KM_ZERO((caddr_t)&acr, sizeof(acr)); + (void) sprintf(acr.acp_intf, "%s%d", pip->pif_name, + pip->pif_unit); + KM_COPY((caddr_t)acp, (caddr_t)&acr.acp_cfg, + sizeof(Atm_config)); + + /* + * Copy data to user buffer + */ + err = copyout((caddr_t)&acr, aip->air_buf_addr, + sizeof(acr)); + if (err) + break; + + /* + * Update buffer pointer/count + */ + aip->air_buf_addr += sizeof(acr); + aip->air_buf_len -= sizeof(acr); + break; + + case AIOCS_INF_VST: + /* + * Pass off to device-specific handler + */ + cup = (Cmn_unit *)arg; + if (cup == NULL) + err = ENXIO; + else + err = (*cup->cu_ioctl)(code, data, arg); + break; + + default: + err = ENOSYS; + } + + return ( err ); +} + + +/* + * Register a Network Convergence Module + * + * Each ATM network convergence module must register itself here before + * it will receive network interface status notifications. + * + * Arguments: + * ncp pointer to network convergence definition structure + * + * Returns: + * 0 registration successful + * errno registration failed - reason indicated + * + */ +int +atm_netconv_register(ncp) + struct atm_ncm *ncp; +{ + struct atm_ncm *tdp; + int s = splnet(); + + /* + * See if we need to be initialized + */ + if (!atm_init) + atm_initialize(); + + /* + * Validate protocol family + */ + if (ncp->ncm_family > AF_MAX) { + (void) splx(s); + return (EINVAL); + } + + /* + * Ensure no duplicates + */ + for (tdp = atm_netconv_head; tdp != NULL; tdp = tdp->ncm_next) { + if (tdp->ncm_family == ncp->ncm_family) { + (void) splx(s); + return (EEXIST); + } + } + + /* + * Add module to list + */ + LINK2TAIL(ncp, struct atm_ncm, atm_netconv_head, ncm_next); + + /* + * Add new interface output function + */ + atm_ifouttbl[ncp->ncm_family] = ncp->ncm_ifoutput; + + (void) splx(s); + return (0); +} + + +/* + * De-register an ATM Network Convergence Module + * + * Each ATM network convergence provider must de-register its registered + * service(s) before terminating. Specifically, loaded kernel modules + * must de-register their services before unloading themselves. + * + * Arguments: + * ncp pointer to network convergence definition structure + * + * Returns: + * 0 de-registration successful + * errno de-registration failed - reason indicated + * + */ +int +atm_netconv_deregister(ncp) + struct atm_ncm *ncp; +{ + int found, s = splnet(); + + /* + * Remove module from list + */ + UNLINKF(ncp, struct atm_ncm, atm_netconv_head, ncm_next, found); + + if (!found) { + (void) splx(s); + return (ENOENT); + } + + /* + * Remove module's interface output function + */ + atm_ifouttbl[ncp->ncm_family] = NULL; + + (void) splx(s); + return (0); +} + + +/* + * Attach an ATM Network Interface + * + * Before an ATM network interface can be used by the system, the owning + * device interface must attach the network interface using this function. + * The physical interface for this network interface must have been previously + * registered (using atm_interface_register). The network interface will be + * added to the kernel's interface list and to the physical interface's list. + * The caller is responsible for initializing the control block fields. + * + * Arguments: + * nip pointer to atm network interface control block + * + * Returns: + * 0 attach successful + * errno attach failed - reason indicated + * + */ +int +atm_nif_attach(nip) + struct atm_nif *nip; +{ + struct atm_pif *pip, *pip2; + struct ifnet *ifp; + struct atm_ncm *ncp; + int s; + + ifp = &nip->nif_if; + pip = nip->nif_pif; + + s = splimp(); + + /* + * Verify physical interface is registered + */ + for (pip2 = atm_interface_head; pip2 != NULL; pip2 = pip2->pif_next) { + if (pip == pip2) + break; + } + if ((pip == NULL) || (pip2 == NULL)) { + (void) splx(s); + return (EFAULT); + } + + /* + * Add to system interface list + */ + if_attach(ifp); + + /* + * Add to physical interface list + */ + LINK2TAIL(nip, struct atm_nif, pip->pif_nif, nif_pnext); + + /* + * Notify network convergence modules of new network i/f + */ + for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) { + int err; + + err = (*ncp->ncm_stat)(NCM_ATTACH, nip, 0); + if (err) { + atm_nif_detach(nip); + (void) splx(s); + return (err); + } + } + + (void) splx(s); + return (0); +} + + +/* + * Detach an ATM Network Interface + * + * Before an ATM network interface control block can be freed, all kernel + * references to/from this block must be released. This function will delete + * all routing references to the interface and free all interface addresses + * for the interface. The network interface will then be removed from the + * kernel's interface list and from the owning physical interface's list. + * The caller is responsible for free'ing the control block. + * + * Arguments: + * nip pointer to atm network interface control block + * + * Returns: + * none + * + */ +void +atm_nif_detach(nip) + struct atm_nif *nip; +{ + struct atm_ncm *ncp; + int s, i; + struct ifnet *ifp = &nip->nif_if; + struct ifaddr *ifa; + struct in_ifaddr *ia; + struct radix_node_head *rnh; + + + s = splimp(); + + /* + * Notify convergence modules of network i/f demise + */ + for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) { + (void) (*ncp->ncm_stat)(NCM_DETACH, nip, 0); + } + + /* + * Mark interface down + */ + if_down(ifp); + + /* + * Free all interface routes and addresses + */ + while (1) { + IFP_TO_IA(ifp, ia); + if (ia == NULL) + break; + + /* Delete interface route */ + in_ifscrub(ifp, ia); + + /* Remove interface address from queues */ + ifa = &ia->ia_ifa; + TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); + TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link); + + /* Free interface address */ + IFAFREE(ifa); + } + + /* + * Delete all remaining routes using this interface + * Unfortuneatly the only way to do this is to slog through + * the entire routing table looking for routes which point + * to this interface...oh well... + */ + for (i = 1; i <= AF_MAX; i++) { + if ((rnh = rt_tables[i]) == NULL) + continue; + (void) rnh->rnh_walktree(rnh, atm_netif_rtdel, ifp); + } + + /* + * Remove from system interface list (ie. if_detach()) + */ + TAILQ_REMOVE(&ifnet, ifp, if_link); + + /* + * Remove from physical interface list + */ + UNLINK(nip, struct atm_nif, nip->nif_pif->pif_nif, nif_pnext); + + (void) splx(s); +} + + +/* + * Delete Routes for a Network Interface + * + * Called for each routing entry via the rnh->rnh_walktree() call above + * to delete all route entries referencing a detaching network interface. + * + * Arguments: + * rn pointer to node in the routing table + * arg argument passed to rnh->rnh_walktree() - detaching interface + * + * Returns: + * 0 successful + * errno failed - reason indicated + * + */ +static int +atm_netif_rtdel(rn, arg) + struct radix_node *rn; + void *arg; +{ + struct rtentry *rt = (struct rtentry *)rn; + struct ifnet *ifp = arg; + int err; + + if (rt->rt_ifp == ifp) { + + /* + * Protect (sorta) against walktree recursion problems + * with cloned routes + */ + if ((rt->rt_flags & RTF_UP) == 0) + return (0); + + err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, + rt_mask(rt), rt->rt_flags, + (struct rtentry **) NULL); + if (err) { + log(LOG_WARNING, "atm_netif_rtdel: error %d\n", err); + } + } + + return (0); +} + + +/* + * Set an ATM Network Interface address + * + * This is called from a device interface when processing an SIOCSIFADDR + * ioctl request. We just notify all convergence modules of the new address + * and hope everyone has non-overlapping interests, since if someone reports + * an error we don't go back and tell everyone to undo the change. + * + * Arguments: + * nip pointer to atm network interface control block + * ifa pointer to new interface address + * + * Returns: + * 0 set successful + * errno set failed - reason indicated + * + */ +int +atm_nif_setaddr(nip, ifa) + struct atm_nif *nip; + struct ifaddr *ifa; +{ + struct atm_ncm *ncp; + int err = 0, s = splnet(); + + /* + * Notify convergence modules of network i/f change + */ + for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) { + err = (*ncp->ncm_stat)(NCM_SETADDR, nip, (int)ifa); + if (err) + break; + } + (void) splx(s); + + return (err); +} + + +/* + * ATM Interface Packet Output + * + * All ATM network interfaces must have their ifnet if_output address set to + * this function. Since no existing network layer code is to be modified + * for ATM support, this function serves as the hook to allow network output + * packets to be assigned to their proper outbound VCC. Each network address + * family which is to be supported over ATM must be assigned an output + * packet processing function via atm_netconv_register(). + * + * Arguments: + * ifp pointer to ifnet structure + * m pointer to packet buffer chain to be output + * dst pointer to packet's network destination address + * + * Returns: + * 0 packet queued to interface + * errno output failed - reason indicated + * + */ +int +#if (defined(BSD) && (BSD >= 199103)) +atm_ifoutput(ifp, m, dst, rt) +#else +atm_ifoutput(ifp, m, dst) +#endif + struct ifnet *ifp; + KBuffer *m; + struct sockaddr *dst; +#if (defined(BSD) && (BSD >= 199103)) + struct rtentry *rt; +#endif +{ + u_short fam = dst->sa_family; + int (*func)__P((struct ifnet *, KBuffer *, + struct sockaddr *)); + + /* + * Validate address family + */ + if (fam > AF_MAX) { + KB_FREEALL(m); + return (EAFNOSUPPORT); + } + + /* + * Hand packet off for dst-to-VCC mapping + */ + func = atm_ifouttbl[fam]; + if (func == NULL) { + KB_FREEALL(m); + return (EAFNOSUPPORT); + } + return ((*func)(ifp, m, dst)); +} + + +/* + * Handle interface ioctl requests. + * + * Arguments: + * ifp pointer to network interface structure + * cmd IOCTL cmd + * data arguments to/from ioctl + * + * Returns: + * error errno value + */ +static int +atm_if_ioctl(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + register struct ifreq *ifr = (struct ifreq *)data; + struct atm_nif *nip = (struct atm_nif *)ifp; + int error = 0; + int s = splnet(); + + switch ( cmd ) + { + case SIOCGIFADDR: + KM_COPY ( (caddr_t)&(nip->nif_pif->pif_macaddr), + (caddr_t)ifr->ifr_addr.sa_data, + sizeof(struct mac_addr) ); + break; + + case SIOCSIFADDR: + error = atm_nif_setaddr ( nip, (struct ifaddr *)data); + ifp->if_flags |= IFF_UP | IFF_RUNNING | IFF_BROADCAST; + break; + + case SIOCGIFFLAGS: + *(short *)data = ifp->if_flags; + break; + + case SIOCSIFFLAGS: + break; + + default: + error = EINVAL; + break; + } + + (void) splx(s); + return ( error ); +} + + +/* + * Parse interface name + * + * Parses an interface name string into a name and a unit component. + * + * Arguments: + * name pointer to interface name string + * namep address to store interface name + * size size available at namep + * unitp address to store interface unit number + * + * Returns: + * 0 name parsed + * else parse error + * + */ +static int +atm_ifparse(name, namep, size, unitp) + char *name; + char *namep; + int size; + int *unitp; +{ + char *cp, *np; + int len = 0, unit = 0; + + /* + * Separate supplied string into name and unit parts. + */ + cp = name; + np = namep; + while (*cp) { + if (*cp >= '0' && *cp <= '9') + break; + if (++len >= size) + return (-1); + *np++ = *cp++; + } + *np = '\0'; + while (*cp && *cp >= '0' && *cp <= '9') + unit = 10 * unit + *cp++ - '0'; + + *unitp = unit; + + return (0); +} + + +/* + * Locate ATM physical interface via name + * + * Uses the supplied interface name string to locate a registered + * ATM physical interface. + * + * Arguments: + * name pointer to interface name string + * + * Returns: + * 0 interface not found + * else pointer to atm physical interface structure + * + */ +struct atm_pif * +atm_pifname(name) + char *name; +{ + struct atm_pif *pip; + char n[IFNAMSIZ]; + int unit; + + /* + * Break down name + */ + if (atm_ifparse(name, n, sizeof(n), &unit)) + return ((struct atm_pif *)0); + + /* + * Look for the physical interface + */ + for (pip = atm_interface_head; pip; pip = pip->pif_next) { + if ((pip->pif_unit == unit) && (strcmp(pip->pif_name, n) == 0)) + break; + } + + return (pip); +} + + +/* + * Locate ATM network interface via name + * + * Uses the supplied interface name string to locate an ATM network interface. + * + * Arguments: + * name pointer to interface name string + * + * Returns: + * 0 interface not found + * else pointer to atm network interface structure + * + */ +struct atm_nif * +atm_nifname(name) + char *name; +{ + struct atm_pif *pip; + struct atm_nif *nip; + char n[IFNAMSIZ]; + int unit; + + /* + * Break down name + */ + if (atm_ifparse(name, n, sizeof(n), &unit)) + return ((struct atm_nif *)0); + + /* + * Search thru each physical interface + */ + for (pip = atm_interface_head; pip; pip = pip->pif_next) { + /* + * Looking for network interface + */ + for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) { + struct ifnet *ifp = (struct ifnet *)nip; + if ((ifp->if_unit == unit) && + (strcmp(ifp->if_name, n) == 0)) + return (nip); + } + } + return (NULL); +} + |