/* * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* ----------------------------------------------------------------------------- * * Theory of operation : * * This contains the family shim for PPP. This is really a shim, since all * the work is done in the interface layer * ----------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------- Includes ----------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ppp_defs.h" // public ppp values #include "ppp_fam.h" #include "ppp_ip.h" #include "if_ppplink.h" // public link API #include "ppp_domain.h" /* ----------------------------------------------------------------------------- Definitions ----------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------- Forward declarations ----------------------------------------------------------------------------- */ static int ppp_fam_add_if(struct ifnet *ifp); static int ppp_fam_del_if(struct ifnet *ifp); static int ppp_fam_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag); static int ppp_fam_del_proto(struct if_proto *proto, u_long dl_tag); static int ppp_fam_demux(struct ifnet *ifp, struct mbuf *m, char *frame_header, void *if_proto_ptr); static int ppp_fam_frameout(struct ifnet *ifp, struct mbuf **m0, struct sockaddr *ndest, char *edst, char *ppp_type); /* ----------------------------------------------------------------------------- Globals ----------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------- init function ----------------------------------------------------------------------------- */ int ppp_fam_init() { int ret; struct dlil_ifmod_reg_str mod; // register the module bzero(&mod, sizeof(struct dlil_ifmod_reg_str)); mod.add_if = ppp_fam_add_if; mod.del_if = ppp_fam_del_if; mod.add_proto = ppp_fam_add_proto; mod.del_proto = ppp_fam_del_proto; ret = dlil_reg_if_modules(APPLE_IF_FAM_PPP, &mod); LOGRETURN(ret, ret, "ppp_fam_init: dlil_reg_if_modules error = 0x%x\n"); return 0; } /* ----------------------------------------------------------------------------- terminate function ----------------------------------------------------------------------------- */ int ppp_fam_dispose() { int ret; ret = dlil_dereg_if_modules(APPLE_IF_FAM_PPP); LOGRETURN(ret, ret, "ppp_fam_dispose: dlil_dereg_if_modules error = 0x%x\n"); return 0; } /* ----------------------------------------------------------------------------- add interface function called from dlil when a new interface is attached for that family needs to set the frameout and demux dlil specific functions in the ifp ----------------------------------------------------------------------------- */ int ppp_fam_add_if(struct ifnet *ifp) { struct ppp_fam *pppfam; LOGDBG(ifp, (LOGVAL, "ppp_fam_add_if, ifp = 0x%x\n", ifp)); MALLOC(pppfam, struct ppp_fam *, sizeof(struct ppp_fam), M_TEMP, M_WAIT); if (!pppfam) { LOGDBG(ifp, (LOGVAL, "ppp_fam_ifoutput : Can't allocate interface family structure\n")); return 1; } bzero(pppfam, sizeof(struct ppp_fam)); ifp->family_cookie = (u_long)pppfam; ifp->if_framer = ppp_fam_frameout; ifp->if_demux = ppp_fam_demux; return 0; } /* ----------------------------------------------------------------------------- delete interface function called from dlil when an interface is detached for that family ----------------------------------------------------------------------------- */ int ppp_fam_del_if(struct ifnet *ifp) { LOGDBG(ifp, (LOGVAL, "ppp_fam_del_if, ifp = 0x%x\n", ifp)); if (ifp->family_cookie) { FREE(ifp->family_cookie, M_TEMP); ifp->family_cookie = 0; } return 0; } /* ----------------------------------------------------------------------------- add protocol function called from dlil when a network protocol is attached for an interface from that family (i.e ip is attached through ppp_attach_ip) ----------------------------------------------------------------------------- */ int ppp_fam_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag) { struct ifnet *ifp = proto->ifp; struct ppp_fam *pppfam = (struct ppp_fam *)ifp->family_cookie; struct dlil_demux_desc *desc = TAILQ_FIRST(desc_head); u_short protocol = 0; if (desc) protocol = *((u_short *)desc->native_type); LOGDBG(ifp, (LOGVAL, "ppp_fam_add_proto = %d, ifp = 0x%x\n", protocol, ifp)); switch (protocol) { case PPP_IP: if (pppfam->ip_tag) // protocol already registered return EEXIST; pppfam->ip_tag = dl_tag; pppfam->ip_proto = proto; break; case PPP_IPV6: if (pppfam->ipv6_tag) // protocol already registered return EEXIST; pppfam->ipv6_tag = dl_tag; pppfam->ipv6_proto = proto; break; default: return EINVAL; // happen for unknown protocol, or for empty descriptor } return 0; } /* ----------------------------------------------------------------------------- delete protocol function called from dlil when a network protocol is detached for an interface from that family (i.e ip is attached through ppp_detach_ip) ----------------------------------------------------------------------------- */ int ppp_fam_del_proto(struct if_proto *proto, u_long dl_tag) { struct ifnet *ifp = proto->ifp; struct ppp_fam *pppfam = (struct ppp_fam *)ifp->family_cookie; LOGDBG(ifp, (LOGVAL, "ppp_fam_del_proto, ifp = 0x%x\n", ifp)); if (dl_tag == pppfam->ip_tag) { pppfam->ip_tag = 0; pppfam->ip_proto = 0; } if (dl_tag == pppfam->ipv6_tag) { pppfam->ipv6_tag = 0; pppfam->ipv6_proto = 0; } return 0; } /* ----------------------------------------------------------------------------- demux function ----------------------------------------------------------------------------- */ int ppp_fam_demux(struct ifnet *ifp, struct mbuf *m, char *frame_header, void *if_proto_ptr) { struct ppp_fam *pppfam = (struct ppp_fam *)ifp->family_cookie; u_int16_t proto; proto = frame_header[0]; if (!proto & 0x1) { // lowest bit set for lowest byte of protocol proto = (proto << 8) + frame_header[1]; } switch (proto) { case PPP_IP: *(struct if_proto **)if_proto_ptr = pppfam->ip_proto; break; case PPP_IPV6: *(struct if_proto **)if_proto_ptr = pppfam->ipv6_proto; break; default : LOGDBG(ifp, (LOGVAL, "ppp_fam_demux, ifp = 0x%x, bad proto = 0x%x\n", ifp, proto)); return ENOENT; // should never happen } return 0; } /* ----------------------------------------------------------------------------- a network packet needs to be send through the interface. add the ppp header to the packet (as a network interface, we only worry about adding our protocol number) ----------------------------------------------------------------------------- */ int ppp_fam_frameout(struct ifnet *ifp, struct mbuf **m0, struct sockaddr *ndest, char *edst, char *ppp_type) { M_PREPEND (*m0, 2, M_DONTWAIT); if (*m0 == 0) { LOGDBG(ifp, (LOGVAL, "ppp_fam_ifoutput : no memory for transmit header\n")); ifp->if_oerrors++; return EJUSTRETURN; // just return, because the buffer was freed in m_prepend } // place protocol number at the beginning of the mbuf *mtod(*m0, u_int16_t *) = htons(*(u_int16_t *)ppp_type); return 0; }