1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* ----------------------------------------------------------------------------- 25 * 26 * Theory of operation : 27 * 28 * This file implements the ip protocol module for the ppp interface 29 * 30----------------------------------------------------------------------------- */ 31 32/* ----------------------------------------------------------------------------- 33Includes 34----------------------------------------------------------------------------- */ 35 36#include <sys/param.h> 37#include <sys/mbuf.h> 38#include <sys/socket.h> 39#include <sys/syslog.h> 40#include <sys/systm.h> 41#include <sys/malloc.h> 42#include <sys/sockio.h> 43#include <kern/locks.h> 44 45#include <net/if.h> 46#include <net/kpi_protocol.h> 47 48#include <netinet/in.h> 49#include <netinet/in_systm.h> 50#include <netinet/in_var.h> 51#include <netinet/ip.h> 52#include <netinet/udp.h> 53#include <netinet/bootp.h> 54 55#include "ppp_defs.h" // public ppp values 56#include "ppp_ip.h" 57#include "ppp_domain.h" 58#include "ppp_if.h" 59#include "if_ppplink.h" 60 61 62/* ----------------------------------------------------------------------------- 63Definitions 64----------------------------------------------------------------------------- */ 65 66/* ----------------------------------------------------------------------------- 67Forward declarations 68----------------------------------------------------------------------------- */ 69 70static errno_t ppp_ip_input(ifnet_t ifp, protocol_family_t protocol, 71 mbuf_t packet, char* header); 72static errno_t ppp_ip_preoutput(ifnet_t ifp, protocol_family_t protocol, 73 mbuf_t *packet, const struct sockaddr *dest, 74 void *route, char *frame_type, char *link_layer_dest); 75static errno_t ppp_ip_ioctl(ifnet_t ifp, protocol_family_t protocol, 76 u_long command, void* argument); 77 78/* ----------------------------------------------------------------------------- 79Globals 80----------------------------------------------------------------------------- */ 81extern lck_mtx_t *ppp_domain_mutex; 82 83/* ----------------------------------------------------------------------------- 84init function 85----------------------------------------------------------------------------- */ 86int ppp_ip_init(int init_arg) 87{ 88 return proto_register_plumber(PF_INET, APPLE_IF_FAM_PPP, 89 ppp_ip_attach, ppp_ip_detach); 90} 91 92/* ----------------------------------------------------------------------------- 93terminate function 94----------------------------------------------------------------------------- */ 95int ppp_ip_dispose(int term_arg) 96{ 97 proto_unregister_plumber(PF_INET, APPLE_IF_FAM_PPP); 98 return 0; 99} 100 101/* ----------------------------------------------------------------------------- 102attach the PPPx interface ifp to the network protocol IP, 103called when the ppp interface is ready for ppp traffic 104----------------------------------------------------------------------------- */ 105errno_t ppp_ip_attach(ifnet_t ifp, protocol_family_t protocol) 106{ 107 int ret; 108 struct ifnet_attach_proto_param reg; 109 struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); 110 111 LOGDBG(ifp, ("ppp_ip_attach: name = %s, unit = %d\n", ifnet_name(ifp), ifnet_unit(ifp))); 112 113 if (wan->ip_attached) 114 return 0; // already attached 115 116 bzero(®, sizeof(struct ifnet_attach_proto_param)); 117 118 reg.input = ppp_ip_input; 119 reg.pre_output = ppp_ip_preoutput; 120 reg.ioctl = ppp_ip_ioctl; 121 ret = ifnet_attach_protocol(ifp, PF_INET, ®); 122 LOGRETURN(ret, ret, "ppp_ip_attach: ifnet_attach_protocol error = 0x%x\n"); 123 124 LOGDBG(ifp, ("ppp_i6_attach: ifnet_attach_protocol family = 0x%x\n", protocol)); 125 ifnet_find_by_name("lo0", &wan->lo_ifp); 126 wan->ip_attached = 1; 127 128 return 0; 129} 130 131/* ----------------------------------------------------------------------------- 132detach the PPPx interface ifp from the network protocol IP, 133called when the ppp interface stops ip traffic 134----------------------------------------------------------------------------- */ 135void ppp_ip_detach(ifnet_t ifp, protocol_family_t protocol) 136{ 137 int ret; 138 struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); 139 140 LOGDBG(ifp, ("ppp_ip_detach\n")); 141 142 if (!wan->ip_attached) 143 return; // already detached 144 145 ifnet_release(wan->lo_ifp); 146 wan->lo_ifp = 0; 147 148 ret = ifnet_detach_protocol(ifp, PF_INET); 149 if (ret) 150 IOLog("ppp_ip_detach: ifnet_detach_protocol error = 0x%x\n", ret); 151 152 wan->ip_attached = 0; 153} 154 155/* ----------------------------------------------------------------------------- 156called from dlil when an ioctl is sent to the interface 157----------------------------------------------------------------------------- */ 158errno_t ppp_ip_ioctl(ifnet_t ifp, protocol_family_t protocol, 159 u_long command, void* argument) 160{ 161 struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); 162 struct sockaddr_in addr, dstaddr; 163 int error = 0; 164 165 switch (command) { 166 167 case SIOCSIFADDR: 168 case SIOCAIFADDR: 169 LOGDBG(ifp, ("ppp_ip_ioctl: cmd = SIOCSIFADDR/SIOCAIFADDR\n")); 170 171 error = ifaddr_address(argument, (struct sockaddr *)&addr, sizeof (addr)); 172 if (error != 0) { 173 error = EAFNOSUPPORT; 174 break; 175 } 176 177 // only an IPv4 address should arrive here 178 if (addr.sin_family != AF_INET) { 179 error = EAFNOSUPPORT; 180 break; 181 } 182 183 error = ifaddr_dstaddress(argument, (struct sockaddr *)&dstaddr, sizeof (dstaddr)); 184 if (error != 0) { 185 error = EAFNOSUPPORT; 186 break; 187 } 188 189 // only an IPv4 address should arrive here 190 if (dstaddr.sin_family != AF_INET) { 191 error = EAFNOSUPPORT; 192 break; 193 } 194 195 wan->ip_src.s_addr = addr.sin_addr.s_addr; 196 wan->ip_dst.s_addr = dstaddr.sin_addr.s_addr; 197 break; 198 199 default : 200 error = EOPNOTSUPP; 201 } 202 203 return error; 204} 205 206/* ----------------------------------------------------------------------------- 207called from dlil when a packet from the interface is to be dispatched to 208the specific network protocol attached by dl_tag. 209the network protocol has been determined earlier by the demux function. 210the packet is in the mbuf chain m without 211the frame header, which is provided separately. (not used) 212----------------------------------------------------------------------------- */ 213errno_t ppp_ip_input(ifnet_t ifp, protocol_family_t protocol, 214 mbuf_t packet, char* header) 215{ 216 217 LOGMBUF("ppp_ip_input", packet); 218 219 if (proto_input(PF_INET, packet)) 220 mbuf_freem(packet); 221 222 return 0; 223} 224 225/* ----------------------------------------------------------------------------- 226pre_output function 227----------------------------------------------------------------------------- */ 228errno_t ppp_ip_preoutput(ifnet_t ifp, protocol_family_t protocol, 229 mbuf_t *packet, const struct sockaddr *dest, 230 void *route, char *frame_type, char *link_layer_dest) 231{ 232 errno_t err; 233 struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); 234 u_int16_t ftype = PPP_IP; 235 236 LOGMBUF("ppp_ip_preoutput", *packet); 237 238 lck_mtx_lock(ppp_domain_mutex); 239 240#if 0 241 (*packet)->m_flags &= ~M_HIGHPRI; 242 243 /* If this packet has the "low delay" bit set in the IP header, 244 set priority bit for the packet. */ 245 ip = mtod(*packet, struct ip *); 246 if (ip->ip_tos & IPTOS_LOWDELAY) 247 (*packet)->m_flags |= M_HIGHPRI; 248#endif 249 250 if ((wan->sc_flags & SC_LOOP_LOCAL) 251 && (!memcmp(&((struct sockaddr_in *)(void*)dest)->sin_addr.s_addr, &wan->ip_src.s_addr, sizeof(struct in_addr))) // Wcast-align fix - memcmp for unaligned compare 252 && wan->lo_ifp) { 253 err = ifnet_output(wan->lo_ifp, PF_INET, *packet, 0, (struct sockaddr *)dest); 254 lck_mtx_unlock(ppp_domain_mutex); 255 return (err ? err : EJUSTRETURN); 256 } 257 lck_mtx_unlock(ppp_domain_mutex); 258 memcpy(frame_type, &ftype, sizeof(u_int16_t)); // Wcast-align fix - memcpy for unaligned move 259 return 0; 260} 261 262/* ----------------------------------------------------------------------------- 263Compare the source address of the packet with the source address of the interface 264----------------------------------------------------------------------------- */ 265int ppp_ip_af_src_out(ifnet_t ifp, char *pkt) 266{ 267 struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); 268 struct ip *ip; 269 270 // Wcast-align fixes - use memcmp for unaligned move 271 ip = (struct ip *)(void*)pkt; 272 return (memcmp(&ip->ip_src.s_addr, &wan->ip_src.s_addr, sizeof(struct in_addr)) == 0 ? 0 : 1); 273} 274 275/* ----------------------------------------------------------------------------- 276Compare the source address of the packet with the dst address of the interface 277----------------------------------------------------------------------------- */ 278int ppp_ip_af_src_in(ifnet_t ifp, char *pkt) 279{ 280 struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); 281 struct ip *ip; 282 283 // Wcast-align fixes - use memcmp for unaligned accesses 284 ip = (struct ip *)(void*)pkt; 285 return (memcmp(&ip->ip_src.s_addr, &wan->ip_dst.s_addr, sizeof(struct in_addr)) == 0 ? 0 : 1); 286} 287 288/* ----------------------------------------------------------------------------- 289Check if the packet is a bootp packet for us 290----------------------------------------------------------------------------- */ 291int ppp_ip_bootp_client_in(ifnet_t ifp, char *pkt) 292{ 293 struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); 294 struct ip *ip; 295 struct udphdr udp; 296 297 // Wcast-align fixes - use memcmp and memcpy for unaligned accesses 298 ip = (struct ip *)(void*)pkt; 299 if (!memcmp(&ip->ip_dst.s_addr, &wan->ip_src.s_addr, sizeof(struct in_addr)) && ip->ip_p == IPPROTO_UDP) { 300 301 memcpy(&udp, pkt + sizeof(struct ip), sizeof(struct udphdr)); 302 if (udp.uh_sport == htons(IPPORT_BOOTPS) && udp.uh_dport == htons(IPPORT_BOOTPC)) { 303 return 1; 304 } 305 } 306 307 return 0; 308} 309 310/* ----------------------------------------------------------------------------- 311Check if the packet is a broadcast bootp packet 312----------------------------------------------------------------------------- */ 313int ppp_ip_bootp_server_in(ifnet_t ifp, char *pkt) 314{ 315 //struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); 316 struct ip *ip; 317 struct udphdr udp; 318 u_int32_t val4; 319 320 // Wcast-align fixes - use memcmp and memcpy for unaligned accesses 321 ip = (struct ip *)(void*)pkt; 322 val4 = htonl(INADDR_BROADCAST); 323 if (!memcmp(&ip->ip_dst.s_addr, &val4, sizeof(struct in_addr)) && ip->ip_p == IPPROTO_UDP) { 324 325 memcpy(&udp, pkt + sizeof(struct ip), sizeof(struct udphdr)); 326 if (udp.uh_sport == htons(IPPORT_BOOTPC) && udp.uh_dport == htons(IPPORT_BOOTPS)) { 327 return 1; 328 } 329 } 330 331 return 0; 332} 333 334 335