/* * 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@ */ #include #include #include #include #include #include #include #include /* include ppp domain as we use the ppp domain family */ #include "../../../Family/ppp_domain.h" #include "PPPoE.h" #include "pppoe_rfc.h" #include "pppoe_dlil.h" extern struct ifnet* ifbyfamily(u_long family, short unit); /* ----------------------------------------------------------------------------- Definitions ----------------------------------------------------------------------------- */ struct pppoe_if { TAILQ_ENTRY(pppoe_if) next; u_short unit; u_short refcnt; ifnet_t ifp; }; /* ----------------------------------------------------------------------------- Declarations ----------------------------------------------------------------------------- */ static errno_t pppoe_dlil_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t packet, char* header); static errno_t pppoe_dlil_pre_output(ifnet_t ifp, protocol_family_t protocol, mbuf_t *packet, const struct sockaddr *dest, void *route, char *frame_type, char *link_layer_dest); static void pppoe_dlil_event(ifnet_t ifp, protocol_family_t protocol, const struct kev_msg *event); static errno_t pppoe_dlil_ioctl(ifnet_t ifp, protocol_family_t protocol, u_int32_t command, void* argument); static void pppoe_dlil_detaching(u_int16_t unit); /* ----------------------------------------------------------------------------- Globals ----------------------------------------------------------------------------- */ TAILQ_HEAD(, pppoe_if) pppoe_if_head; extern lck_mtx_t *ppp_domain_mutex; /* ----------------------------------------------------------------------------- intialize pppoe datalink attachment strutures ----------------------------------------------------------------------------- */ int pppoe_dlil_init() { TAILQ_INIT(&pppoe_if_head); return 0; } /* ----------------------------------------------------------------------------- dispose pppoe datalink structures can't dispose if clients are still attached ----------------------------------------------------------------------------- */ int pppoe_dlil_dispose() { if (!TAILQ_EMPTY(&pppoe_if_head)) return 1; return 0; } /* ----------------------------------------------------------------------------- attach pppoe to ethernet unit returns 0 and the ifp when successfully attached ----------------------------------------------------------------------------- */ int pppoe_dlil_attach(u_short unit, ifnet_t *ifpp) { struct pppoe_if *pppoeif; ifnet_t ifp; int ret; char ifname[20]; struct ifnet_attach_proto_param reg; struct ifnet_demux_desc desc[2]; u_int16_t ctrl_protocol = htons(PPPOE_ETHERTYPE_CTRL); u_int16_t data_protocol = htons(PPPOE_ETHERTYPE_DATA); TAILQ_FOREACH(pppoeif, &pppoe_if_head, next) { if (pppoeif->unit == unit) { *ifpp = pppoeif->ifp; pppoeif->refcnt++; return 0; } } MALLOC(pppoeif, struct pppoe_if *, sizeof(struct pppoe_if), M_TEMP, M_WAITOK); if (!pppoeif) { log(LOGVAL, "pppoe_dlil_attach : Can't allocate attachment structure\n"); return 1; } sprintf(ifname, "en%d", unit); if (ifnet_find_by_name(ifname, &ifp)) { log(LOGVAL, "pppoe_dlil_attach : Can't find interface unit %d\n", unit); return 1; } bzero(®, sizeof(struct ifnet_attach_proto_param)); // define demux for PPPoE desc[0].type = DLIL_DESC_ETYPE2; desc[0].data = (char *)&ctrl_protocol; desc[0].datalen = sizeof(ctrl_protocol); desc[1].type = DLIL_DESC_ETYPE2; desc[1].data = (char *)&data_protocol; desc[1].datalen = sizeof(data_protocol); reg.demux_list = desc; reg.demux_count = 2; reg.input = pppoe_dlil_input; reg.pre_output = pppoe_dlil_pre_output; reg.event = pppoe_dlil_event; reg.ioctl = pppoe_dlil_ioctl; lck_mtx_unlock(ppp_domain_mutex); ret = ifnet_attach_protocol(ifp, PF_PPP, ®); if (ret) { lck_mtx_lock(ppp_domain_mutex); log(LOGVAL, "pppoe_dlil_attach: error = 0x%x\n", ret); ifnet_release(ifp); FREE(pppoeif, M_TEMP); return ret; } bzero(pppoeif, sizeof(struct pppoe_if)); lck_mtx_lock(ppp_domain_mutex); pppoeif->ifp = ifp; pppoeif->unit = unit; pppoeif->refcnt = 1; *ifpp = pppoeif->ifp; TAILQ_INSERT_TAIL(&pppoe_if_head, pppoeif, next); return 0; } /* ----------------------------------------------------------------------------- detach pppoe from ethernet unit ----------------------------------------------------------------------------- */ int pppoe_dlil_detach(ifnet_t ifp) { struct pppoe_if *pppoeif; if (ifp == 0) return 0; TAILQ_FOREACH(pppoeif, &pppoe_if_head, next) { if (pppoeif->ifp == ifp) { pppoeif->refcnt--; if (pppoeif->refcnt == 0) { lck_mtx_unlock(ppp_domain_mutex); ifnet_detach_protocol(ifp, PF_PPP); ifnet_release(ifp); lck_mtx_lock(ppp_domain_mutex); TAILQ_REMOVE(&pppoe_if_head, pppoeif, next); FREE(pppoeif, M_TEMP); } break; } } return 0; } /* ----------------------------------------------------------------------------- ethernet unit wants to detach ----------------------------------------------------------------------------- */ void pppoe_dlil_detaching(u_int16_t unit) { struct pppoe_if *pppoeif; lck_mtx_lock(ppp_domain_mutex); TAILQ_FOREACH(pppoeif, &pppoe_if_head, next) { if (pppoeif->unit == unit) { pppoe_rfc_lower_detaching(pppoeif->ifp); break; } } lck_mtx_unlock(ppp_domain_mutex); } /* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ errno_t pppoe_dlil_pre_output(ifnet_t ifp, protocol_family_t protocol, mbuf_t *packet, const struct sockaddr *dest, void *route, char *frame_type, char *link_layer_dest) { struct ether_header *eh; //log(LOGVAL, "pppenet_pre_output, ifp = 0x%x\n", ifp); // fill in expected type and dst from previously set dst_netaddr // looks complicated to me eh = (struct ether_header *)dest->sa_data; bcopy(eh->ether_dhost, link_layer_dest, sizeof(eh->ether_dhost)); *(u_int16_t *)frame_type = eh->ether_type; //log(LOGVAL, "pppoe_dlil_pre_output ifname %s%d, addr = 0x%x:%x:%x:%x:%x:%x, frame_type = 0x%lx\n", ifnet_name(ifp), ifnet_unit(ifp), link_layer_dest[0], link_layer_dest[1], // link_layer_dest[2], link_layer_dest[3], link_layer_dest[4], link_layer_dest[5], *(u_int16_t *)frame_type); return 0; } /* ----------------------------------------------------------------------------- should handle network up/down... ----------------------------------------------------------------------------- */ void pppoe_dlil_event(ifnet_t ifp, protocol_family_t protocol, const struct kev_msg *event) { struct net_event_data *ev_data; // check for detaching if (event->vendor_code == KEV_VENDOR_APPLE && event->kev_class == KEV_NETWORK_CLASS && event->kev_subclass == KEV_DL_SUBCLASS && event->event_code == KEV_DL_IF_DETACHING) { ev_data = (struct net_event_data*)event->dv[0].data_ptr; if (ev_data->if_family == APPLE_IF_FAM_ETHERNET) pppoe_dlil_detaching(ev_data->if_unit); } } /* ----------------------------------------------------------------------------- pppoe specific ioctl, nothing defined ----------------------------------------------------------------------------- */ errno_t pppoe_dlil_ioctl(ifnet_t ifp, protocol_family_t protocol, u_int32_t command, void* argument) { //log(LOGVAL, "pppoe_dlil_ioctl, ifp = %s%n\n", ifnet_name(ifp), ifnet_unit(ifp)); return 0; } /* ----------------------------------------------------------------------------- * Process a received pppoe packet; * the packet is in the mbuf chain m without * the ether header, which is provided separately. ----------------------------------------------------------------------------- */ errno_t pppoe_dlil_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t packet, char* header) { //unsigned char *p = frame_header; //unsigned char *data; struct ether_header *eh = (struct ether_header *)header; //log(LOGVAL, "pppenet_input, ifp = %s%d\n", ifp->if_name, ifp->if_unit); //log(LOGVAL, "pppenet_input: enet_header dst : %x:%x:%x:%x:%x:%x - src %x:%x:%x:%x:%x:%x - type - %4x\n", //p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8],p[9],p[10],p[11],ntohs(*(u_int16_t *)&p[12])); //data = mtod(m, unsigned char *); //log(LOGVAL, "pppenet_input: data 0x %x %x %x %x %x %x\n", // data[0],data[1],data[2],data[3],data[4],data[5]); // only the ifp discriminate client at this point // pppoe will have to look at the session id to select the appropriate socket lck_mtx_lock(ppp_domain_mutex); pppoe_rfc_lower_input(ifp, packet, header + ETHER_ADDR_LEN, ntohs(eh->ether_type)); lck_mtx_unlock(ppp_domain_mutex); return 0; } /* ----------------------------------------------------------------------------- called from pppenet_proto when data need to be sent ----------------------------------------------------------------------------- */ int pppoe_dlil_output(ifnet_t ifp, mbuf_t m, u_int8_t *to, u_int16_t typ) { struct ether_header *eh; struct sockaddr sa; eh = (struct ether_header *)sa.sa_data; (void)bcopy(to, eh->ether_dhost, sizeof(eh->ether_dhost)); eh->ether_type = htons(typ); sa.sa_family = AF_UNSPEC; sa.sa_len = sizeof(sa); lck_mtx_unlock(ppp_domain_mutex); ifnet_output(ifp, PF_PPP, m, 0, &sa); lck_mtx_lock(ppp_domain_mutex); return 0; }