1/*
2 * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <sys/types.h>
34#include <sys/queue.h>
35#include <stdio.h>
36#include <string.h>
37#include <stdlib.h>
38#include <stdint.h>
39
40#include "pcap-int.h"
41#include "pcap-util.h"
42
43
44void
45pcap_clear_if_infos(pcap_t * pcap)
46{
47	int i;
48
49	if (pcap->if_infos != NULL) {
50		for (i = 0; i < pcap->if_info_count; i++)
51			pcap_free_if_info(pcap, pcap->if_infos[i]);
52
53		free(pcap->if_infos);
54		pcap->if_infos = NULL;
55	}
56	pcap->if_info_count = 0;
57
58	return;
59}
60
61struct pcap_if_info *
62pcap_find_if_info_by_name(pcap_t * pcap, const char *name)
63{
64	int i;
65
66	for (i = 0; i < pcap->if_info_count; i++) {
67		if (strcmp(name, pcap->if_infos[i]->if_name) == 0)
68			return (pcap->if_infos[i]);
69	}
70	return (NULL);
71}
72
73struct pcap_if_info *
74pcap_find_if_info_by_id(pcap_t * pcap, int if_id)
75{
76	int i;
77
78	for (i = 0; i < pcap->if_info_count; i++) {
79		if (if_id == pcap->if_infos[i]->if_id)
80			return (pcap->if_infos[i]);
81	}
82	return (NULL);
83}
84
85void
86pcap_free_if_info(pcap_t * pcap, struct pcap_if_info *if_info)
87{
88	if (if_info != NULL) {
89		int i;
90
91		for (i = 0; i < pcap->if_info_count; i++) {
92			if (pcap->if_infos[i] == if_info) {
93				pcap->if_infos[i] = NULL;
94				break;
95			}
96		}
97
98		pcap_freecode(&if_info->if_filter_program);
99		free(if_info);
100	}
101}
102
103struct pcap_if_info *
104pcap_add_if_info(pcap_t * pcap, const char *name,
105		 int if_id, int linktype, int snaplen)
106{
107	struct pcap_if_info *if_info = NULL;
108	size_t ifname_len = strlen(name);
109	struct pcap_if_info **newarray;
110
111	pcap->cleanup_extra_op = pcap_ng_init_section_info;
112
113	/*
114	 * Stash the interface name after the structure
115	 */
116	if_info = calloc(1, sizeof(struct pcap_if_info) + ifname_len + 1);
117	if (if_info == NULL) {
118		snprintf(pcap->errbuf, PCAP_ERRBUF_SIZE,
119				 "%s: calloc() failed", __func__);
120		return (NULL);
121	}
122	if_info->if_name = (char *)(if_info + 1);
123	if (ifname_len > 0)
124		bcopy(name, if_info->if_name, ifname_len);
125	if_info->if_name[ifname_len] = 0;
126	if (if_id == -1)
127		if_info->if_id = pcap->if_info_count;
128	else
129		if_info->if_id = if_id;
130	if_info->if_linktype = linktype;
131	if_info->if_snaplen = snaplen;
132
133	/*
134	 * The compilation of a BPF filter expression depends on
135	 * the DLT so we store the program in the if_info
136	 */
137	if (pcap->filter_str != NULL && *pcap->filter_str != 0) {
138		if (pcap_compile_nopcap(if_info->if_snaplen,
139					if_info->if_linktype,
140					&if_info->if_filter_program,
141					pcap->filter_str, 0, PCAP_NETMASK_UNKNOWN) == -1) {
142			snprintf(pcap->errbuf, PCAP_ERRBUF_SIZE,
143					 "%s: pcap_compile_nopcap() failed", __func__);
144			free(if_info);
145			return (NULL);
146		}
147	}
148
149	/*
150	 * Resize pointer array
151	 */
152	newarray = realloc(pcap->if_infos,
153			   (pcap->if_info_count + 1) * sizeof(struct pcap_if_info *));
154	if (newarray == NULL) {
155		snprintf(pcap->errbuf, PCAP_ERRBUF_SIZE,
156				 "%s: realloc() failed", __func__);
157		pcap_free_if_info(pcap, if_info);
158		return (NULL);
159	}
160	pcap->if_infos = newarray;
161	pcap->if_infos[pcap->if_info_count] = if_info;
162	pcap->if_info_count += 1;
163
164	return (if_info);
165}
166
167void
168pcap_clear_proc_infos(pcap_t * pcap)
169{
170	int i;
171
172	if (pcap->proc_infos != NULL) {
173		for (i = 0; i < pcap->proc_info_count; i++)
174			pcap_free_proc_info(pcap, pcap->proc_infos[i]);
175
176		free(pcap->proc_infos);
177		pcap->proc_infos = NULL;
178	}
179	pcap->proc_info_count = 0;
180
181	return;
182}
183
184struct pcap_proc_info *
185pcap_find_proc_info(pcap_t * pcap, uint32_t pid, const char *name)
186{
187	int i;
188
189	for (i = 0; i < pcap->proc_info_count; i++) {
190		struct pcap_proc_info *proc_info = pcap->proc_infos[i];
191
192		if (pid == proc_info->proc_pid &&
193			strcmp(name, proc_info->proc_name) == 0)
194			return (proc_info);
195	}
196	return (NULL);
197}
198
199struct pcap_proc_info *
200pcap_find_proc_info_by_index(pcap_t * pcap, uint32_t index)
201{
202	int i;
203
204	for (i = 0; i < pcap->proc_info_count; i++) {
205		struct pcap_proc_info *proc_info = pcap->proc_infos[i];
206
207		if (index == proc_info->proc_index)
208			return (proc_info);
209	}
210	return (NULL);
211}
212
213void
214pcap_free_proc_info(pcap_t * pcap, struct pcap_proc_info *proc_info)
215{
216
217	if (proc_info != NULL) {
218		int i;
219
220		for (i = 0; i < pcap->proc_info_count; i++) {
221			if (pcap->proc_infos[i] == proc_info) {
222				pcap->proc_infos[i] = NULL;
223				break;
224			}
225		}
226		free(proc_info);
227	}
228}
229
230struct pcap_proc_info *
231pcap_add_proc_info(pcap_t * pcap, uint32_t pid, const char *name)
232{
233	struct pcap_proc_info *proc_info = NULL;
234	size_t name_len = strlen(name);
235	struct pcap_proc_info **newarray;
236
237	pcap->cleanup_extra_op = pcap_ng_init_section_info;
238
239	/*
240	 * Stash the process name after the structure
241	 */
242	proc_info = calloc(1, sizeof(struct pcap_proc_info) + name_len + 1);
243	if (proc_info == NULL) {
244		snprintf(pcap->errbuf, PCAP_ERRBUF_SIZE,
245			 "%s: calloc() failed", __func__);
246		return (NULL);
247	}
248	proc_info->proc_name = (char *)(proc_info + 1);
249	if (name_len > 0)
250		bcopy(name, proc_info->proc_name, name_len);
251	proc_info->proc_name[name_len] = 0;
252	proc_info->proc_pid = pid;
253	proc_info->proc_index = pcap->proc_info_count;
254
255	/*
256	 * Resize pointer array
257	 */
258	newarray = realloc(pcap->proc_infos,
259			   (pcap->proc_info_count + 1) * sizeof(struct pcap_proc_info *));
260	if (newarray == NULL) {
261		snprintf(pcap->errbuf, PCAP_ERRBUF_SIZE,
262			 "%s: malloc() failed", __func__);
263		pcap_free_proc_info(pcap, proc_info);
264		return (NULL);
265	}
266	pcap->proc_infos = newarray;
267	pcap->proc_infos[pcap->proc_info_count] = proc_info;
268	pcap->proc_info_count += 1;
269
270	return (proc_info);
271}
272
273int
274pcap_set_filter_info(pcap_t *pcap, const char *str, int optimize, bpf_u_int32 netmask)
275{
276	if (pcap->filter_str != NULL)
277		free(pcap->filter_str);
278	if (str == NULL)
279		pcap->filter_str = NULL;
280	else {
281		pcap->filter_str = strdup(str);
282		if (pcap->filter_str == NULL)
283			return (PCAP_ERROR);
284	}
285
286	return (0);
287}
288
289void
290pcap_ng_init_section_info(pcap_t *p)
291{
292	p->shb_added = 0;
293	pcap_clear_if_infos(p);
294	pcap_clear_proc_infos(p);
295
296}
297
298