1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22/* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#include <sys/types.h> 28#include <sys/stream.h> 29#include <net/bpf.h> 30#include <net/bpfdesc.h> 31#include <inet/ipnet.h> 32 33/* 34 * This file implements the function calls for ipnet that translate the 35 * calls from BPF into the correct arguments and functions inside of the 36 * ipnet device. 37 */ 38static const char *ipnet_bpf_name(uintptr_t); 39static void ipnet_bpf_client_close(uintptr_t); 40static const char *ipnet_bpf_client_name(uintptr_t); 41static int ipnet_bpf_client_open(uintptr_t, uintptr_t *); 42static void ipnet_bpf_close(uintptr_t); 43static int ipnet_bpf_getdlt(uintptr_t, uint_t *); 44static int ipnet_bpf_getlinkid(const char *, datalink_id_t *, zoneid_t); 45static int ipnet_bpf_getzone(uintptr_t, zoneid_t *); 46static int ipnet_bpf_open(const char *, uintptr_t *, zoneid_t); 47static uintptr_t ipnet_bpf_promisc_add(uintptr_t, int, void *, 48 uintptr_t *, int); 49static void ipnet_bpf_promisc_remove(uintptr_t); 50static void ipnet_bpf_sdu_get(uintptr_t, uint_t *); 51static int ipnet_bpf_tx(uintptr_t, mblk_t *); 52static int ipnet_bpf_type(uintptr_t); 53 54bpf_provider_t bpf_ipnet = { 55 BPR_IPNET, 56 ipnet_bpf_open, 57 ipnet_bpf_close, 58 ipnet_bpf_name, 59 ipnet_bpf_type, 60 ipnet_bpf_sdu_get, 61 ipnet_bpf_tx, 62 ipnet_bpf_promisc_add, 63 ipnet_bpf_promisc_remove, 64 ipnet_bpf_getlinkid, 65 ipnet_bpf_client_close, 66 ipnet_bpf_client_name, 67 ipnet_bpf_client_open, 68 ipnet_bpf_getzone, 69 ipnet_bpf_getdlt, 70}; 71 72/*ARGSUSED*/ 73static int 74ipnet_bpf_open(const char *name, uintptr_t *mhandlep, zoneid_t zoneid) 75{ 76 if (zoneid == ALL_ZONES) 77 zoneid = GLOBAL_ZONEID; 78 return (ipnet_open_byname(name, (ipnetif_t **)mhandlep, zoneid)); 79} 80 81/*ARGSUSED*/ 82static void 83ipnet_bpf_close(uintptr_t mhandle) 84{ 85 ipnet_close_byhandle((ipnetif_t *)mhandle); 86} 87 88static const char * 89ipnet_bpf_name(uintptr_t mhandle) 90{ 91 return (ipnet_name((ipnetif_t *)mhandle)); 92} 93 94/*ARGSUSED*/ 95static int 96ipnet_bpf_type(uintptr_t mhandle) 97{ 98 return (DL_IPNET); 99} 100 101/*ARGSUSED*/ 102static void 103ipnet_bpf_sdu_get(uintptr_t mhandle, uint_t *mtup) 104{ 105 /* 106 * The choice of 65535 is arbitrary, it could be any smaller number 107 * but it does matche the current default choice of libpcap as the 108 * packet snap size. 109 */ 110 *mtup = 65535; 111} 112 113/*ARGSUSED*/ 114static int 115ipnet_bpf_tx(uintptr_t chandle, mblk_t *pkt) 116{ 117 /* 118 * It is not clear what it would mean to send an ipnet packet, 119 * especially since the ipnet device has been implemented to be 120 * an observation (read-only) instrument. Thus a call to send a 121 * packet using ipnet results in the packet being free'd and an 122 * error returned. 123 */ 124 freemsg(pkt); 125 126 return (EBADF); 127} 128 129/* 130 * BPF does not provide the means to select which SAP is being sniffed, 131 * so for the purpose of ipnet, all BPF clients are in SAP promiscuous 132 * mode. 133 */ 134static uintptr_t 135ipnet_bpf_promisc_add(uintptr_t chandle, int how, void *arg, 136 uintptr_t *promisc, int flags) 137{ 138 int newhow; 139 140 /* 141 * Map the mac values into ipnet values. 142 */ 143 switch (how) { 144 case MAC_CLIENT_PROMISC_ALL : 145 newhow = DL_PROMISC_PHYS; 146 flags = IPNET_PROMISC_PHYS|IPNET_PROMISC_SAP; 147 break; 148 case MAC_CLIENT_PROMISC_MULTI : 149 newhow = DL_PROMISC_MULTI; 150 flags = IPNET_PROMISC_MULTI|IPNET_PROMISC_SAP; 151 break; 152 default : 153 newhow = 0; 154 break; 155 } 156 157 return (ipnet_promisc_add((void *)chandle, newhow, 158 arg, promisc, flags)); 159} 160 161static void 162ipnet_bpf_promisc_remove(uintptr_t phandle) 163{ 164 ipnet_promisc_remove((void *)phandle); 165} 166 167static int 168ipnet_bpf_client_open(uintptr_t mhandle, uintptr_t *chandlep) 169{ 170 171 return (ipnet_client_open((ipnetif_t *)mhandle, 172 (ipnetif_t **)chandlep)); 173} 174 175/*ARGSUSED*/ 176static void 177ipnet_bpf_client_close(uintptr_t chandle) 178{ 179 ipnet_client_close((ipnetif_t *)chandle); 180} 181 182static const char * 183ipnet_bpf_client_name(uintptr_t chandle) 184{ 185 return (ipnet_bpf_name(chandle)); 186} 187 188static int 189ipnet_bpf_getlinkid(const char *name, datalink_id_t *idp, zoneid_t zoneid) 190{ 191 uint_t index; 192 int error; 193 ipnet_stack_t *ips; 194 195 VERIFY((ips = ipnet_find_by_zoneid(zoneid)) != NULL); 196 197 index = 0; 198 mutex_enter(&ips->ips_event_lock); 199 error = ipnet_get_linkid_byname(name, &index, zoneid); 200 mutex_exit(&ips->ips_event_lock); 201 if (error == 0) 202 *idp = (datalink_id_t)index; 203 ipnet_rele(ips); 204 return (error); 205} 206 207static int 208ipnet_bpf_getzone(uintptr_t handle, zoneid_t *zip) 209{ 210 ipnetif_t *ipnetif; 211 212 ipnetif = (ipnetif_t *)handle; 213 *zip = ipnetif->if_zoneid; 214 return (0); 215} 216 217/*ARGSUSED*/ 218static int 219ipnet_bpf_getdlt(uintptr_t handle, uint_t *dlp) 220{ 221 *dlp = DL_IPNET; 222 return (0); 223} 224