1 /* etherinfo.c - Retrieve ethernet interface info via NETLINK 
  |   1 /* etherinfo.c - Retrieve ethernet interface info via NETLINK 
  | 
  2  *  |   2  *  | 
  3  * Copyright (C) 2009-2011 Red Hat Inc.  |   3  * Copyright (C) 2009-2011 Red Hat Inc.  | 
  4  *  |   4  *  | 
  5  * David Sommerseth <davids@redhat.com>  |   5  * David Sommerseth <davids@redhat.com>  | 
  6  * Parts of this code is based on ideas and solutions in iproute2  |   6  * Parts of this code is based on ideas and solutions in iproute2  | 
  7  *  |   7  *  | 
  8  * This application is free software; you can redistribute it and/or modify it  |   8  * This application is free software; you can redistribute it and/or modify it  | 
  9  * under the terms of the GNU General Public License as published by the Free  |   9  * under the terms of the GNU General Public License as published by the Free  | 
 10  * Software Foundation; version 2.  |  10  * Software Foundation; version 2.  | 
 11  *  |  11  *  | 
 12  * This application is distributed in the hope that it will be useful,  |  12  * This application is distributed in the hope that it will be useful,  | 
 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of  |  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of  | 
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  |  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  | 
 15  * General Public License for more details.  |  15  * General Public License for more details.  | 
 16  */  |  16  */  | 
 17   |  17   | 
 18 #include <Python.h>  |  18 #include <Python.h>  | 
 19 #include <bits/sockaddr.h>  |  19 #include <bits/sockaddr.h>  | 
 20 #include <stdio.h>  |  20 #include <stdio.h>  | 
 21 #include <string.h>  |  21 #include <string.h>  | 
 22 #include <sys/types.h>  |  22 #include <sys/types.h>  | 
 23 #include <unistd.h>  |  23 #include <unistd.h>  | 
 24 #include <fcntl.h>  |  24 #include <fcntl.h>  | 
 25 #include <stdlib.h>  |  25 #include <stdlib.h>  | 
 26 #include <asm/types.h>  |  26 #include <asm/types.h>  | 
 27 #include <sys/socket.h>  |  27 #include <sys/socket.h>  | 
 28 #include <netlink/route/rtnl.h>  |  28 #include <netlink/route/rtnl.h>  | 
 29 #include <assert.h>  |  29 #include <assert.h>  | 
 30 #include <errno.h>  |  30 #include <errno.h>  | 
 31 #include <pthread.h>  |  31 #include <pthread.h>  | 
 32 #include "etherinfo_struct.h"  |  32 #include "etherinfo_struct.h"  | 
 33 #include "etherinfo.h"  |  33 #include "etherinfo.h"  | 
 34   |  34   | 
 35 pthread_mutex_t nlc_counter_mtx = PTHREAD_MUTEX_INITIALIZER;  |  35 pthread_mutex_t nlc_counter_mtx = PTHREAD_MUTEX_INITIALIZER;  | 
 36   |  36   | 
 37 /*  |  37 /*  | 
 38  *  |  38  *  | 
 39  *   Internal functions for working with struct etherinfo  |  39  *   Internal functions for working with struct etherinfo  | 
 40  *  |  40  *  | 
 41  */  |  41  */  | 
 42   |  42   | 
 43 /**  |  43 /**  | 
 44  * Simple macro which makes sure the destination string is freed if used earlier.  |  44  * Simple macro which makes sure the destination string is freed if used earlier.  | 
 45  *  |  45  *  | 
 46  * @param dst Destination pointer  |  46  * @param dst Destination pointer  | 
 47  * @param src Source pointer  |  47  * @param src Source pointer  | 
 48  *  |  48  *  | 
 49  */  |  49  */  | 
 50 #define SET_STR_VALUE(dst, src) {	 \ |  50 #define SET_STR_VALUE(dst, src) {	 \ | 
 51 	if( dst ) {		 \ |  51 	if( dst ) {		 \ | 
 52 		free(dst);	 \  |  52 		free(dst);	 \  | 
 53 	};			 \  |  53 	};			 \  | 
 54 	dst = strdup(src);	 \  |  54 	dst = strdup(src);	 \  | 
 55 	}  |  55 	}  | 
 56   |  56   | 
 57   |  57   | 
 58 /**  |  58 /**  | 
 59  * Frees the memory used by a struct ipv6address pointer chain.  All elements are freed  |  59  * Frees the memory used by a struct ipv6address pointer chain.  All elements are freed  | 
 60  *  |  60  *  | 
 61  * @param ptr  Pointer to a struct ipv6address chain.  |  61  * @param ptr  Pointer to a struct ipv6address chain.  | 
 62  */  |  62  */  | 
 63 void free_ipv6addresses(struct ipv6address *ptr) { |  63 void free_ipv6addresses(struct ipv6address *ptr) { | 
 64 	struct ipv6address *ipv6ptr = ptr;  |  64 	struct ipv6address *ipv6ptr = ptr;  | 
 65   |  65   | 
 66 	while( ipv6ptr ) { |  66 	while( ipv6ptr ) { | 
 67 		struct ipv6address *tmp = ipv6ptr->next;  |  67 		struct ipv6address *tmp = ipv6ptr->next;  | 
 68   |  68   | 
 69 		if( ipv6ptr->address ) { |  69 		if( ipv6ptr->address ) { | 
 70 			free(ipv6ptr->address);  |  70 			free(ipv6ptr->address);  | 
 71 			ipv6ptr->address = NULL;  |  71 			ipv6ptr->address = NULL;  | 
 72 		}  |  72 		}  | 
 73 		memset(ipv6ptr, 0, sizeof(struct ipv6address));  |  73 		memset(ipv6ptr, 0, sizeof(struct ipv6address));  | 
 74 		free(ipv6ptr);  |  74 		free(ipv6ptr);  | 
 75 		ipv6ptr = tmp;  |  75 		ipv6ptr = tmp;  | 
 76 	}  |  76 	}  | 
 77 }  |  77 }  | 
 78   |  78   | 
 79 /**  |  79 /**  | 
 80  * Frees the memory used by struct etherinfo, including all struct ipv6address children.  |  80  * Frees the memory used by struct etherinfo, including all struct ipv6address children.  | 
 81  *  |  81  *  | 
 82  * @param ptr Pointer to a struct etherninfo element  |  82  * @param ptr Pointer to a struct etherninfo element  | 
 83  */  |  83  */  | 
 84 void free_etherinfo(struct etherinfo *ptr)  |  84 void free_etherinfo(struct etherinfo *ptr)  | 
 85 { |  85 { | 
 86 	if( ptr == NULL ) { // Just for safety |  86 	if( ptr == NULL ) { // Just for safety | 
 87 		return;  |  87 		return;  | 
 88 	}  |  88 	}  | 
 89   |  89   | 
 90 	free(ptr->device);  |  90 	free(ptr->device);  | 
 91   |  91   | 
 92 	if( ptr->hwaddress ) { |  92 	if( ptr->hwaddress ) { | 
 93 		free(ptr->hwaddress);  |  93 		free(ptr->hwaddress);  | 
 94 	}  |  94 	}  | 
 95 	if( ptr->ipv4_address ) { |  95 	Py_XDECREF(ptr->ipv4_addresses);  | 
 96 		free(ptr->ipv4_address);  |  96   | 
 97 	}  |  | 
 98 	if( ptr->ipv4_broadcast ) { |  | 
 99 		free(ptr->ipv4_broadcast);  |  | 
100 	}  |  | 
101 	if( ptr->ipv6_addresses ) { |  97 	if( ptr->ipv6_addresses ) { | 
102 		free_ipv6addresses(ptr->ipv6_addresses);  |  98 		free_ipv6addresses(ptr->ipv6_addresses);  | 
103 	}  |  99 	}  | 
104 	free(ptr);  | 100 	free(ptr);  | 
105 }  | 101 }  | 
106   | 102   | 
107   | 103   | 
108 /**  | 104 /**  | 
109  * Add a new IPv6 address record to a struct ipv6address chain  | 105  * Add a new IPv6 address record to a struct ipv6address chain  | 
110  *  | 106  *  | 
111  * @param addrptr    Pointer to the current IPv6 address chain.  | 107  * @param addrptr    Pointer to the current IPv6 address chain.  | 
112  * @param addr       IPv6 address, represented as char * string  | 108  * @param addr       IPv6 address, represented as char * string  | 
113  * @param netmask    IPv6 netmask, as returned by libnl rtnl_addr_get_prefixlen()  | 109  * @param netmask    IPv6 netmask, as returned by libnl rtnl_addr_get_prefixlen()  | 
114  * @param scope      IPV6 address scope, as returned by libnl rtnl_addr_get_scope()  | 110  * @param scope      IPV6 address scope, as returned by libnl rtnl_addr_get_scope()  | 
115  *  | 111  *  | 
116  * @return Returns a new pointer to the chain containing the new element  | 112  * @return Returns a new pointer to the chain containing the new element  | 
117  */  | 113  */  | 
118 struct ipv6address * etherinfo_add_ipv6(struct ipv6address *addrptr, const char *addr, int netmask, int scope) { | 114 struct ipv6address * etherinfo_add_ipv6(struct ipv6address *addrptr, const char *addr, int netmask, int scope) { | 
119 	struct ipv6address *newaddr = NULL;  | 115 	struct ipv6address *newaddr = NULL;  | 
120   | 116   | 
121 	newaddr = calloc(1, sizeof(struct ipv6address)+2);  | 117 	newaddr = calloc(1, sizeof(struct ipv6address)+2);  | 
122 	if( !newaddr ) { | 118 	if( !newaddr ) { | 
123 		fprintf(stderr, "** ERROR ** Could not allocate memory for a new IPv6 address record (%s/%i [%i])",  | 119 		fprintf(stderr, "** ERROR ** Could not allocate memory for a new IPv6 address record (%s/%i [%i])",  | 
124 			addr, netmask, scope);  | 120 			addr, netmask, scope);  | 
125 		return addrptr;  | 121 		return addrptr;  | 
126 	}  | 122 	}  | 
127   | 123   | 
128 	SET_STR_VALUE(newaddr->address, addr);  | 124 	SET_STR_VALUE(newaddr->address, addr);  | 
129 	newaddr->netmask = netmask;  | 125 	newaddr->netmask = netmask;  | 
130 	newaddr->scope = scope;  | 126 	newaddr->scope = scope;  | 
131 	newaddr->next = addrptr;  | 127 	newaddr->next = addrptr;  | 
132 	return newaddr;  | 128 	return newaddr;  | 
133 }  | 129 }  | 
134   | 130   | 
135   | 131   | 
136 /**  | 132 /**  | 
137  *  libnl callback function.  Does the real parsing of a record returned by NETLINK.  This function  | 133  *  libnl callback function.  Does the real parsing of a record returned by NETLINK.  This function  | 
138  *  parses LINK related packets  | 134  *  parses LINK related packets  | 
139  *  | 135  *  | 
140  * @param obj   Pointer to a struct nl_object response  | 136  * @param obj   Pointer to a struct nl_object response  | 
141  * @param arg   Pointer to a struct etherinfo element where the parse result will be saved  | 137  * @param arg   Pointer to a struct etherinfo element where the parse result will be saved  | 
142  */  | 138  */  | 
143 static void callback_nl_link(struct nl_object *obj, void *arg)  | 139 static void callback_nl_link(struct nl_object *obj, void *arg)  | 
144 { | 140 { | 
145 	struct etherinfo *ethi = (struct etherinfo *) arg;  | 141 	struct etherinfo *ethi = (struct etherinfo *) arg;  | 
146 	struct rtnl_link *link = (struct rtnl_link *) obj;  | 142 	struct rtnl_link *link = (struct rtnl_link *) obj;  | 
147 	struct nl_addr *addr = rtnl_link_get_addr(link);  | 143 	struct nl_addr *addr = rtnl_link_get_addr(link);  | 
148 	unsigned int i, len;  | 144 	unsigned int i, len;  | 
149 	unsigned char *binaddr;  | 145 	unsigned char *binaddr;  | 
150 	char hwaddr[130], *ptr;  | 146 	char hwaddr[130], *ptr;  | 
151   | 147   | 
152 	if( (ethi == NULL) || (ethi->hwaddress != NULL) || (addr == NULL) ) { | 148 	if( (ethi == NULL) || (ethi->hwaddress != NULL) || (addr == NULL) ) { | 
153 		return;  | 149 		return;  | 
154 	}  | 150 	}  | 
155   | 151   | 
156 	binaddr = nl_addr_get_binary_addr(addr);  | 152 	binaddr = nl_addr_get_binary_addr(addr);  | 
157 	memset(&hwaddr, 0, 130);  | 153 	memset(&hwaddr, 0, 130);  | 
158 	len = 20;  | 154 	len = 20;  | 
159 	ptr = (char *)&hwaddr;  | 155 	ptr = (char *)&hwaddr;  | 
160 	for( i = 0; i < 6; i++ ) { | 156 	for( i = 0; i < 6; i++ ) { | 
161 		if( i == 0 ) { | 157 		if( i == 0 ) { | 
162 			snprintf(ptr, len, "%02X", *(binaddr+i));  | 158 			snprintf(ptr, len, "%02X", *(binaddr+i));  | 
163 			len -= 2;  | 159 			len -= 2;  | 
164 			ptr += 2;  | 160 			ptr += 2;  | 
165 		} else { | 161 		} else { | 
166 			snprintf(ptr, len, ":%02X", *(binaddr+i));  | 162 			snprintf(ptr, len, ":%02X", *(binaddr+i));  | 
167 			len -= 3;  | 163 			len -= 3;  | 
168 			ptr += 3;  | 164 			ptr += 3;  | 
169 		}  | 165 		}  | 
170 	}  | 166 	}  | 
171 	SET_STR_VALUE(ethi->hwaddress, hwaddr);  | 167 	SET_STR_VALUE(ethi->hwaddress, hwaddr);  | 
172 }  | 168 }  | 
173   | 169   | 
 | 170 /**  | 
 | 171  * For use by callback_nl_address  | 
 | 172  * Returns 0 for success; -1 for error (though this is currently ignored)  | 
 | 173  */  | 
 | 174 static int  | 
 | 175 append_object_for_netlink_address(struct etherinfo *ethi,  | 
 | 176                                   struct nl_object *obj,  | 
 | 177                                   struct rtnl_addr *addr)  | 
 | 178 { | 
 | 179 	PyObject *addr_obj;  | 
 | 180   | 
 | 181 	assert(ethi);  | 
 | 182 	assert(ethi->ipv4_addresses);  | 
 | 183 	assert(addr);  | 
 | 184   | 
 | 185 	addr_obj = make_python_address_from_rtnl_addr(obj, addr);  | 
 | 186 	if (!addr_obj) { | 
 | 187 	  return -1;  | 
 | 188 	}  | 
 | 189   | 
 | 190 	if (-1 == PyList_Append(ethi->ipv4_addresses, addr_obj)) { | 
 | 191 	  Py_DECREF(addr_obj);  | 
 | 192 	  return -1;  | 
 | 193 	}  | 
 | 194   | 
 | 195 	Py_DECREF(addr_obj);  | 
 | 196   | 
 | 197 	/* Success */  | 
 | 198 	return 0;  | 
 | 199 }  | 
174   | 200   | 
175 /**  | 201 /**  | 
176  *  libnl callback function.  Does the real parsing of a record returned by NETLINK.  This function  | 202  *  libnl callback function.  Does the real parsing of a record returned by NETLINK.  This function  | 
177  *  parses ADDRESS related packets  | 203  *  parses ADDRESS related packets  | 
178  *  | 204  *  | 
179  * @param obj   Pointer to a struct nl_object response  | 205  * @param obj   Pointer to a struct nl_object response  | 
180  * @param arg   Pointer to a struct etherinfo element where the parse result will be saved  | 206  * @param arg   Pointer to a struct etherinfo element where the parse result will be saved  | 
181  */  | 207  */  | 
182 static void callback_nl_address(struct nl_object *obj, void *arg)  | 208 static void callback_nl_address(struct nl_object *obj, void *arg)  | 
183 { | 209 { | 
184 	struct etherinfo *ethi = (struct etherinfo *) arg;  | 210 	struct etherinfo *ethi = (struct etherinfo *) arg;  | 
185 	struct nl_addr *addr;  | 211 	struct nl_addr *addr;  | 
186 	char ip_str[66];  | 212 	char ip_str[66];  | 
187 	int family;  | 213 	int family;  | 
188   | 214   | 
189 	if( ethi == NULL ) { | 215 	if( ethi == NULL ) { | 
190 		return;  | 216 		return;  | 
191 	}  | 217 	}  | 
192   | 218   | 
193 	addr = rtnl_addr_get_local((struct rtnl_addr *)obj);  | 219 	addr = rtnl_addr_get_local((struct rtnl_addr *)obj);  | 
194 	family = nl_addr_get_family(addr);  | 220 	family = nl_addr_get_family(addr);  | 
195 	switch( family ) { | 221 	switch( family ) { | 
196 	case AF_INET:  | 222 	case AF_INET:  | 
197 	case AF_INET6:  | 223 	case AF_INET6:  | 
198 		memset(&ip_str, 0, 66);  | 224 		memset(&ip_str, 0, 66);  | 
199 		inet_ntop(family, nl_addr_get_binary_addr(addr), (char *)&ip_str, 64);  | 225 		inet_ntop(family, nl_addr_get_binary_addr(addr), (char *)&ip_str, 64);  | 
200   | 226   | 
201 		if( family == AF_INET ) { | 227 		if( family == AF_INET ) { | 
202 			struct nl_addr *brdcst = rtnl_addr_get_broadcast((struct rtnl_addr *)obj);  | 228                         (void)append_object_for_netlink_address(ethi, obj, (struct rtnl_addr*) addr);  | 
203 			char brdcst_str[66];  |  | 
204   |  | 
205 			SET_STR_VALUE(ethi->ipv4_address, ip_str);  |  | 
206 			ethi->ipv4_netmask = rtnl_addr_get_prefixlen((struct rtnl_addr*) obj);  |  | 
207   |  | 
208 			if( brdcst ) { |  | 
209 				memset(&brdcst_str, 0, 66);  |  | 
210 				inet_ntop(family, nl_addr_get_binary_addr(brdcst), (char *)&brdcst_str, 64);  |  | 
211 				SET_STR_VALUE(ethi->ipv4_broadcast, brdcst_str);  |  | 
212 			}  |  | 
213 		} else { | 229 		} else { | 
214 			ethi->ipv6_addresses = etherinfo_add_ipv6(ethi->ipv6_addresses,  | 230 			ethi->ipv6_addresses = etherinfo_add_ipv6(ethi->ipv6_addresses,  | 
215 								  ip_str,  | 231 								  ip_str,  | 
216 								  rtnl_addr_get_prefixlen((struct rtnl_addr*) obj),  | 232 								  rtnl_addr_get_prefixlen((struct rtnl_addr*) obj),  | 
217 								  rtnl_addr_get_scope((struct rtnl_addr*) obj));  | 233 								  rtnl_addr_get_scope((struct rtnl_addr*) obj));  | 
218 		}  | 234 		}  | 
219 		return;  | 235 		return;  | 
220 	default:  | 236 	default:  | 
221 		return;  | 237 		return;  | 
222 	}  | 238 	}  | 
223 }  | 239 }  | 
224   | 240   | 
225   | 241   | 
226   | 242   | 
227 /*  | 243 /*  | 
228  *  | 244  *  | 
229  *   Exported functions - API frontend  | 245  *   Exported functions - API frontend  | 
230  *  | 246  *  | 
231  */  | 247  */  | 
232   | 248   | 
233 /**  | 249 /**  | 
234  * Dumps the contents of a struct etherinfo element to file  | 250  * Dumps the contents of a struct etherinfo element to file  | 
235  *  | 251  *  | 
236  * @param fp   FILE pointer where to dump  | 252  * @param fp   FILE pointer where to dump  | 
237  * @param ptr  Pointer to a struct etherinfo element  | 253  * @param ptr  Pointer to a struct etherinfo element  | 
238  */  | 254  */  | 
239 void dump_etherinfo(FILE *fp, struct etherinfo *ptr)  | 255 void dump_etherinfo(FILE *fp, struct etherinfo *ptr)  | 
240 { | 256 { | 
241   | 257   | 
242 	fprintf(fp, "*** Interface [%i] %s  ", ptr->index, ptr->device);  | 258 	fprintf(fp, "*** Interface [%i] %s  ", ptr->index, ptr->device);  | 
243 	if( ptr->hwaddress ) { | 259 	if( ptr->hwaddress ) { | 
244 		fprintf(fp, "MAC address: %s", ptr->hwaddress);  | 260 		fprintf(fp, "MAC address: %s", ptr->hwaddress);  | 
245 	}  | 261 	}  | 
246 	fprintf(fp, "\n");  | 262 	fprintf(fp, "\n");  | 
247 	if( ptr->ipv4_address ) { | 263 	if( ptr->ipv4_addresses ) { | 
248 		fprintf(fp, "\tIPv4 Address: %s/%i",  | 264 		Py_ssize_t i;  | 
249 			ptr->ipv4_address, ptr->ipv4_netmask);  | 265 		for (i = 0; i < PyList_Size(ptr->ipv4_addresses); i++) { | 
250 		if( ptr->ipv4_broadcast ) { | 266 			PyNetlinkIPv4Address *addr = (PyNetlinkIPv4Address *)PyList_GetItem(ptr->ipv4_addresses, i);  | 
251 			fprintf(fp, "  -  Broadcast: %s", ptr->ipv4_broadcast);  | 267 			fprintf(fp, "\tIPv4 Address: %s/%i",  | 
252 		}  | 268                                 PyString_AsString(addr->ipv4_address),  | 
253 		fprintf(fp, "\n");  | 269                                 addr->ipv4_netmask);  | 
 | 270                         if( addr->ipv4_broadcast ) { | 
 | 271                               fprintf(fp, "  -  Broadcast: %s", PyString_AsString(addr->ipv4_broadcast));  | 
 | 272                         }  | 
 | 273                         fprintf(fp, "\n");  | 
 | 274                 }  | 
254 	}  | 275 	}  | 
255 	if( ptr->ipv6_addresses ) { | 276 	if( ptr->ipv6_addresses ) { | 
256 		struct ipv6address *ipv6 = ptr->ipv6_addresses;  | 277 		struct ipv6address *ipv6 = ptr->ipv6_addresses;  | 
257   | 278   | 
258 		fprintf(fp, "\tIPv6 addresses:\n");  | 279 		fprintf(fp, "\tIPv6 addresses:\n");  | 
259 		for(; ipv6; ipv6 = ipv6->next) { | 280 		for(; ipv6; ipv6 = ipv6->next) { | 
260 			char scope[66];  | 281 			char scope[66];  | 
261   | 282   | 
262 			rtnl_scope2str(ipv6->scope, scope, 64);  | 283 			rtnl_scope2str(ipv6->scope, scope, 64);  | 
263 			fprintf(fp, "\t		       [%s] %s/%i\n",  | 284 			fprintf(fp, "\t		       [%s] %s/%i\n",  | 
264 				scope, ipv6->address, ipv6->netmask);  | 285 				scope, ipv6->address, ipv6->netmask);  | 
265 		}  | 286 		}  | 
266 	}  | 287 	}  | 
267 	fprintf(fp, "\n");  | 288 	fprintf(fp, "\n");  | 
268 }  | 289 }  | 
269   | 290   | 
270   | 291   | 
271 /**  | 292 /**  | 
272  * Query NETLINK for ethernet configuration  | 293  * Query NETLINK for ethernet configuration  | 
273  *  | 294  *  | 
274  * @param ethinf Pointer to an available struct etherinfo element.  The 'device' member  | 295  * @param ethinf Pointer to an available struct etherinfo element.  The 'device' member  | 
275  *               must contain a valid string to the device to query for information  | 296  *               must contain a valid string to the device to query for information  | 
276  * @param nlc    Pointer to the libnl handle, which is used for the query against NETLINK  | 297  * @param nlc    Pointer to the libnl handle, which is used for the query against NETLINK  | 
277  * @param query  What to query for.  Must be NLQRY_LINK or NLQRY_ADDR.  | 298  * @param query  What to query for.  Must be NLQRY_LINK or NLQRY_ADDR.  | 
278  *  | 299  *  | 
279  * @return Returns 1 on success, otherwise 0.  | 300  * @return Returns 1 on success, otherwise 0.  | 
280  */  | 301  */  | 
281 int get_etherinfo(struct etherinfo_obj_data *data, nlQuery query)  | 302 int get_etherinfo(struct etherinfo_obj_data *data, nlQuery query)  | 
282 { | 303 { | 
283 	struct nl_cache *link_cache;  | 304 	struct nl_cache *link_cache;  | 
284 	struct nl_cache *addr_cache;  | 305 	struct nl_cache *addr_cache;  | 
285 	struct rtnl_addr *addr;  | 306 	struct rtnl_addr *addr;  | 
286 	struct rtnl_link *link;  | 307 	struct rtnl_link *link;  | 
287 	struct etherinfo *ethinf = NULL;  | 308 	struct etherinfo *ethinf = NULL;  | 
288 	int ret = 0;  | 309 	int ret = 0;  | 
289   | 310   | 
290 	if( !data || !data->ethinfo ) { | 311 	if( !data || !data->ethinfo ) { | 
291 		return 0;  | 312 		return 0;  | 
292 	}  | 313 	}  | 
293 	ethinf = data->ethinfo;  | 314 	ethinf = data->ethinfo;  | 
294   | 315   | 
295 	/* Open a NETLINK connection on-the-fly */  | 316 	/* Open a NETLINK connection on-the-fly */  | 
296 	if( !open_netlink(data) ) { | 317 	if( !open_netlink(data) ) { | 
297 		PyErr_Format(PyExc_RuntimeError,  | 318 		PyErr_Format(PyExc_RuntimeError,  | 
298 			     "Could not open a NETLINK connection for %s",  | 319 			     "Could not open a NETLINK connection for %s",  | 
299 			     ethinf->device);  | 320 			     ethinf->device);  | 
300 		return 0;  | 321 		return 0;  | 
301 	}  | 322 	}  | 
302   | 323   | 
303 	/* Find the interface index we're looking up.  | 324 	/* Find the interface index we're looking up.  | 
304 	 * As we don't expect it to change, we're reusing a "cached"  | 325 	 * As we don't expect it to change, we're reusing a "cached"  | 
305 	 * interface index if we have that  | 326 	 * interface index if we have that  | 
306 	 */  | 327 	 */  | 
307 	if( ethinf->index < 0 ) { | 328 	if( ethinf->index < 0 ) { | 
308 		link_cache = rtnl_link_alloc_cache(*data->nlc);  | 329 		link_cache = rtnl_link_alloc_cache(*data->nlc);  | 
309 		ethinf->index = rtnl_link_name2i(link_cache, ethinf->device);  | 330 		ethinf->index = rtnl_link_name2i(link_cache, ethinf->device);  | 
310 		if( ethinf->index < 0 ) { | 331 		if( ethinf->index < 0 ) { | 
311 			return 0;  | 332 			return 0;  | 
312 		}  | 333 		}  | 
313 		nl_cache_free(link_cache);  | 334 		nl_cache_free(link_cache);  | 
314 	}  | 335 	}  | 
315   | 336   | 
316 	/* Query the for requested info vai NETLINK */  | 337 	/* Query the for requested info vai NETLINK */  | 
317 	switch( query ) { | 338 	switch( query ) { | 
318 	case NLQRY_LINK:  | 339 	case NLQRY_LINK:  | 
319 		/* Extract MAC/hardware address of the interface */  | 340 		/* Extract MAC/hardware address of the interface */  | 
320 		link_cache = rtnl_link_alloc_cache(*data->nlc);  | 341 		link_cache = rtnl_link_alloc_cache(*data->nlc);  | 
321 		link = rtnl_link_alloc();  | 342 		link = rtnl_link_alloc();  | 
322 		rtnl_link_set_ifindex(link, ethinf->index);  | 343 		rtnl_link_set_ifindex(link, ethinf->index);  | 
323 		nl_cache_foreach_filter(link_cache, (struct nl_object *)link, callback_nl_link, ethinf);  | 344 		nl_cache_foreach_filter(link_cache, (struct nl_object *)link, callback_nl_link, ethinf);  | 
324 		rtnl_link_put(link);  | 345 		rtnl_link_put(link);  | 
325 		nl_cache_free(link_cache);  | 346 		nl_cache_free(link_cache);  | 
326 		ret = 1;  | 347 		ret = 1;  | 
327 		break;  | 348 		break;  | 
328   | 349   | 
329 	case NLQRY_ADDR:  | 350 	case NLQRY_ADDR:  | 
330 		/* Extract IP address information */  | 351 		/* Extract IP address information */  | 
331 		addr_cache = rtnl_addr_alloc_cache(*data->nlc);  | 352 		addr_cache = rtnl_addr_alloc_cache(*data->nlc);  | 
332 		addr = rtnl_addr_alloc();  | 353 		addr = rtnl_addr_alloc();  | 
333 		rtnl_addr_set_ifindex(addr, ethinf->index);  | 354 		rtnl_addr_set_ifindex(addr, ethinf->index);  | 
334   | 355   | 
335                 /* Make sure we don't have any old IPv6 addresses saved */  | 356                 /* Make sure we don't have any old IPv6 addresses saved */  | 
336                 if( ethinf->ipv6_addresses ) { | 357                 if( ethinf->ipv6_addresses ) { | 
337                         free_ipv6addresses(ethinf->ipv6_addresses);  | 358                         free_ipv6addresses(ethinf->ipv6_addresses);  | 
338                         ethinf->ipv6_addresses = NULL;  | 359                         ethinf->ipv6_addresses = NULL;  | 
339                 }  | 360                 }  | 
340   | 361   | 
 | 362                 /* Likewise for IPv4 addresses: */  | 
 | 363                 Py_XDECREF(ethinf->ipv4_addresses);  | 
 | 364                 ethinf->ipv4_addresses = PyList_New(0);  | 
 | 365                 if (!ethinf->ipv4_addresses) { | 
 | 366                         return 0;  | 
 | 367                 }  | 
 | 368   | 
341                 /* Retrieve all address information */  | 369                 /* Retrieve all address information */  | 
342 		nl_cache_foreach_filter(addr_cache, (struct nl_object *)addr, callback_nl_address, ethinf);  | 370 		nl_cache_foreach_filter(addr_cache, (struct nl_object *)addr, callback_nl_address, ethinf);  | 
343 		rtnl_addr_put(addr);  | 371 		rtnl_addr_put(addr);  | 
344 		nl_cache_free(addr_cache);  | 372 		nl_cache_free(addr_cache);  | 
345 		ret = 1;  | 373 		ret = 1;  | 
346 		break;  | 374 		break;  | 
347   | 375   | 
348 	default:  | 376 	default:  | 
349 		ret = 0;  | 377 		ret = 0;  | 
350 	}  | 378 	}  | 
351 	return ret;  | 379 	return ret;  | 
352 }  | 380 }  | 
353   | 381   | 
354   | 382   | 
355 /**  | 383 /**  | 
356  * Connects to the NETLINK interface.  This will be called  | 384  * Connects to the NETLINK interface.  This will be called  | 
357  * for each etherinfo object being generated, and it will  | 385  * for each etherinfo object being generated, and it will  | 
358  * keep a separate file descriptor open for each object  | 386  * keep a separate file descriptor open for each object  | 
359  *  | 387  *  | 
360  * @param data etherinfo_obj_data structure  | 388  * @param data etherinfo_obj_data structure  | 
361  *  | 389  *  | 
362  * @return Returns 1 on success, otherwise 0.  | 390  * @return Returns 1 on success, otherwise 0.  | 
363  */  | 391  */  | 
364 int open_netlink(struct etherinfo_obj_data *data)  | 392 int open_netlink(struct etherinfo_obj_data *data)  | 
365 { | 393 { | 
366 	if( !data ) { | 394 	if( !data ) { | 
367 		return 0;  | 395 		return 0;  | 
368 	}  | 396 	}  | 
369   | 397   | 
370 	/* Reuse already established NETLINK connection, if a connection exists */  | 398 	/* Reuse already established NETLINK connection, if a connection exists */  | 
371 	if( *data->nlc ) { | 399 	if( *data->nlc ) { | 
372 		/* If this object has not used NETLINK earlier, tag it as a user */  | 400 		/* If this object has not used NETLINK earlier, tag it as a user */  | 
373 		if( !data->nlc_active ) { | 401 		if( !data->nlc_active ) { | 
374 			pthread_mutex_lock(&nlc_counter_mtx);  | 402 			pthread_mutex_lock(&nlc_counter_mtx);  | 
375 			(*data->nlc_users)++;  | 403 			(*data->nlc_users)++;  | 
376 			pthread_mutex_unlock(&nlc_counter_mtx);  | 404 			pthread_mutex_unlock(&nlc_counter_mtx);  | 
377 		}  | 405 		}  | 
378 		data->nlc_active = 1;  | 406 		data->nlc_active = 1;  | 
379 		return 1;  | 407 		return 1;  | 
380 	}  | 408 	}  | 
381   | 409   | 
382 	/* No earlier connections exists, establish a new one */  | 410 	/* No earlier connections exists, establish a new one */  | 
383 	*data->nlc = nl_handle_alloc();  | 411 	*data->nlc = nl_handle_alloc();  | 
384 	nl_connect(*data->nlc, NETLINK_ROUTE);  | 412 	nl_connect(*data->nlc, NETLINK_ROUTE);  | 
385 	if( (*data->nlc != NULL) ) { | 413 	if( (*data->nlc != NULL) ) { | 
386 		/* Force O_CLOEXEC flag on the NETLINK socket */  | 414 		/* Force O_CLOEXEC flag on the NETLINK socket */  | 
387 		if( fcntl(nl_socket_get_fd(*data->nlc), F_SETFD, FD_CLOEXEC) == -1 ) { | 415 		if( fcntl(nl_socket_get_fd(*data->nlc), F_SETFD, FD_CLOEXEC) == -1 ) { | 
388 			fprintf(stderr,  | 416 			fprintf(stderr,  | 
389 				"**WARNING** Failed to set O_CLOEXEC on NETLINK socket: %s\n",  | 417 				"**WARNING** Failed to set O_CLOEXEC on NETLINK socket: %s\n",  | 
390 				strerror(errno));  | 418 				strerror(errno));  | 
391 		}  | 419 		}  | 
392   | 420   | 
393 		/* Tag this object as an active user */  | 421 		/* Tag this object as an active user */  | 
394 		pthread_mutex_lock(&nlc_counter_mtx);  | 422 		pthread_mutex_lock(&nlc_counter_mtx);  | 
395 		(*data->nlc_users)++;  | 423 		(*data->nlc_users)++;  | 
396 		pthread_mutex_unlock(&nlc_counter_mtx);  | 424 		pthread_mutex_unlock(&nlc_counter_mtx);  | 
397 		data->nlc_active = 1;  | 425 		data->nlc_active = 1;  | 
398 		return 1;  | 426 		return 1;  | 
399 	} else { | 427 	} else { | 
400 		return 0;  | 428 		return 0;  | 
401 	}  | 429 	}  | 
402 }  | 430 }  | 
403   | 431   | 
404   | 432   | 
405 /**  | 433 /**  | 
406  * Closes the NETLINK connection.  This should be called automatically whenever  | 434  * Closes the NETLINK connection.  This should be called automatically whenever  | 
407  * the corresponding etherinfo object is deleted.  | 435  * the corresponding etherinfo object is deleted.  | 
408  *  | 436  *  | 
409  * @param ptr  Pointer to the pointer of struct nl_handle, which contains the NETLINK connection  | 437  * @param ptr  Pointer to the pointer of struct nl_handle, which contains the NETLINK connection  | 
410  */  | 438  */  | 
411 void close_netlink(struct etherinfo_obj_data *data)  | 439 void close_netlink(struct etherinfo_obj_data *data)  | 
412 { | 440 { | 
413 	if( !data || !(*data->nlc) ) { | 441 	if( !data || !(*data->nlc) ) { | 
414 		return;  | 442 		return;  | 
415 	}  | 443 	}  | 
416   | 444   | 
417 	/* Untag this object as a NETLINK user */  | 445 	/* Untag this object as a NETLINK user */  | 
418 	data->nlc_active = 0;  | 446 	data->nlc_active = 0;  | 
419 	pthread_mutex_lock(&nlc_counter_mtx);  | 447 	pthread_mutex_lock(&nlc_counter_mtx);  | 
420 	(*data->nlc_users)--;  | 448 	(*data->nlc_users)--;  | 
421 	pthread_mutex_unlock(&nlc_counter_mtx);  | 449 	pthread_mutex_unlock(&nlc_counter_mtx);  | 
422   | 450   | 
423 	/* Don't close the connection if there are more users */  | 451 	/* Don't close the connection if there are more users */  | 
424 	if( *data->nlc_users > 0) { | 452 	if( *data->nlc_users > 0) { | 
425 		return;  | 453 		return;  | 
426 	}  | 454 	}  | 
427   | 455   | 
428 	/* Close NETLINK connection */  | 456 	/* Close NETLINK connection */  | 
429 	nl_close(*data->nlc);  | 457 	nl_close(*data->nlc);  | 
430 	nl_handle_destroy(*data->nlc);  | 458 	nl_handle_destroy(*data->nlc);  | 
431 	*data->nlc = NULL;  | 459 	*data->nlc = NULL;  | 
432 }  | 460 }  | 
  | 
  | 
  2  * Copyright (C) 2009-2011 Red Hat Inc.  |   2  * Copyright (C) 2009-2011 Red Hat Inc.  | 
  3  *  |   3  *  | 
  4  * David Sommerseth <davids@redhat.com>  |   4  * David Sommerseth <davids@redhat.com>  | 
  5  *  |   5  *  | 
  6  * This application is free software; you can redistribute it and/or modify it  |   6  * This application is free software; you can redistribute it and/or modify it  | 
  7  * under the terms of the GNU General Public License as published by the Free  |   7  * under the terms of the GNU General Public License as published by the Free  | 
  8  * Software Foundation; version 2.  |   8  * Software Foundation; version 2.  | 
  9  *  |   9  *  | 
 10  * This application is distributed in the hope that it will be useful,  |  10  * This application is distributed in the hope that it will be useful,  | 
 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of  |  11  * but WITHOUT ANY WARRANTY; without even the implied warranty of  | 
 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  |  12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  | 
 13  * General Public License for more details.  |  13  * General Public License for more details.  | 
 14  */  |  14  */  | 
 15   |  15   | 
 16   |  16   | 
 17 /**  |  17 /**  | 
 18  * @file   etherinfo_obj.c  |  18  * @file   etherinfo_obj.c  | 
 19  * @author David Sommerseth <davids@redhat.com>  |  19  * @author David Sommerseth <davids@redhat.com>  | 
 20  * @date   Fri Sep  4 18:41:28 2009  |  20  * @date   Fri Sep  4 18:41:28 2009  | 
 21  *  |  21  *  | 
 22  * @brief  Python ethtool.etherinfo class functions.  |  22  * @brief  Python ethtool.etherinfo class functions.  | 
 23  *  |  23  *  | 
 24  */  |  24  */  | 
 25   |  25   | 
 26 #include <Python.h>  |  26 #include <Python.h>  | 
 27 #include "structmember.h"  |  27 #include "structmember.h"  | 
 28   |  28   | 
 29 #include <netlink/route/rtnl.h>  |  29 #include <netlink/route/rtnl.h>  | 
 30 #include "etherinfo_struct.h"  |  30 #include "etherinfo_struct.h"  | 
 31 #include "etherinfo.h"  |  31 #include "etherinfo.h"  | 
 32   |  32   | 
 33 extern PyTypeObject ethtool_etherinfoIPv6Type;  |  33 extern PyTypeObject ethtool_etherinfoIPv6Type;  | 
 34   |  34   | 
 35 /**  |  35 /**  | 
 36  * ethtool.etherinfo deallocator - cleans up when a object is deleted  |  36  * ethtool.etherinfo deallocator - cleans up when a object is deleted  | 
 37  *  |  37  *  | 
 38  * @param self etherinfo_py object structure  |  38  * @param self etherinfo_py object structure  | 
 39  */  |  39  */  | 
 40 void _ethtool_etherinfo_dealloc(etherinfo_py *self)  |  40 void _ethtool_etherinfo_dealloc(etherinfo_py *self)  | 
 41 { |  41 { | 
 42 	if( self->data ) { |  42 	if( self->data ) { | 
 43 		close_netlink(self->data);  |  43 		close_netlink(self->data);  | 
 44   |  44   | 
 45 		if( self->data->ethinfo ) { |  45 		if( self->data->ethinfo ) { | 
 46 			free_etherinfo(self->data->ethinfo);  |  46 			free_etherinfo(self->data->ethinfo);  | 
 47 		}  |  47 		}  | 
 48 		free(self->data);  |  48 		free(self->data);  | 
 49 	}  |  49 	}  | 
 50 	self->ob_type->tp_free((PyObject*)self);  |  50 	self->ob_type->tp_free((PyObject*)self);  | 
 51 }  |  51 }  | 
 52   |  52   | 
 53   |  53   | 
 54 /**  |  54 /**  | 
 55  * ethtool.etherinfo function, creating a new etherinfo object  |  55  * ethtool.etherinfo function, creating a new etherinfo object  | 
 56  *  |  56  *  | 
 57  * @param type  |  57  * @param type  | 
 58  * @param args  |  58  * @param args  | 
 59  * @param kwds  |  59  * @param kwds  | 
 60  *  |  60  *  | 
 61  * @return Returns in PyObject with the new object on success, otherwise NULL  |  61  * @return Returns in PyObject with the new object on success, otherwise NULL  | 
 62  */  |  62  */  | 
 63 PyObject *_ethtool_etherinfo_new(PyTypeObject *type, PyObject *args, PyObject *kwds)  |  63 PyObject *_ethtool_etherinfo_new(PyTypeObject *type, PyObject *args, PyObject *kwds)  | 
 64 { |  64 { | 
 65 	etherinfo_py *self;  |  65 	etherinfo_py *self;  | 
 66   |  66   | 
 67 	self = (etherinfo_py *)type->tp_alloc(type, 0);  |  67 	self = (etherinfo_py *)type->tp_alloc(type, 0);  | 
 68 	return (PyObject *)self;  |  68 	return (PyObject *)self;  | 
 69 }  |  69 }  | 
 70   |  70   | 
 71   |  71   | 
 72 /**  |  72 /**  | 
 73  * ethtool.etherinfo init (constructor) method.  Makes sure the object is initialised correctly.  |  73  * ethtool.etherinfo init (constructor) method.  Makes sure the object is initialised correctly.  | 
 74  *  |  74  *  | 
 75  * @param self  |  75  * @param self  | 
 76  * @param args  |  76  * @param args  | 
 77  * @param kwds  |  77  * @param kwds  | 
 78  *  |  78  *  | 
 79  * @return Returns 0 on success.  |  79  * @return Returns 0 on success.  | 
 80  */  |  80  */  | 
 81 int _ethtool_etherinfo_init(etherinfo_py *self, PyObject *args, PyObject *kwds)  |  81 int _ethtool_etherinfo_init(etherinfo_py *self, PyObject *args, PyObject *kwds)  | 
 82 { |  82 { | 
 83 	static char *etherinfo_kwlist[] = {"etherinfo_ptr", NULL}; |  83 	static char *etherinfo_kwlist[] = {"etherinfo_ptr", NULL}; | 
 84 	PyObject *ethinf_ptr = NULL;  |  84 	PyObject *ethinf_ptr = NULL;  | 
 85   |  85   | 
 86 	if( !PyArg_ParseTupleAndKeywords(args, kwds, "O", etherinfo_kwlist, ðinf_ptr)) { |  86 	if( !PyArg_ParseTupleAndKeywords(args, kwds, "O", etherinfo_kwlist, ðinf_ptr)) { | 
 87 		PyErr_SetString(PyExc_AttributeError, "Invalid data pointer to constructor");  |  87 		PyErr_SetString(PyExc_AttributeError, "Invalid data pointer to constructor");  | 
 88 		return -1;  |  88 		return -1;  | 
 89 	}  |  89 	}  | 
 90 	self->data = (struct etherinfo_obj_data *) PyCObject_AsVoidPtr(ethinf_ptr);  |  90 	self->data = (struct etherinfo_obj_data *) PyCObject_AsVoidPtr(ethinf_ptr);  | 
 91 	return 0;  |  91 	return 0;  | 
 92 }  |  92 }  | 
 93   |  93   | 
 |  94 /*  | 
 |  95   The old approach of having a single IPv4 address per device meant each result  | 
 |  96   that came in from netlink overwrote the old result.  | 
 |  97   | 
 |  98   Mimic it by returning the last entry in the list (if any).  | 
 |  99   | 
 | 100   The return value is a *borrowed reference* (or NULL)  | 
 | 101 */  | 
 | 102 static PyNetlinkIPv4Address*  | 
 | 103 get_last_address(etherinfo_py *self)  | 
 | 104 { | 
 | 105 	Py_ssize_t size;  | 
 | 106 	PyObject *list;  | 
 | 107   | 
 | 108 	assert(self);  | 
 | 109 	list = self->data->ethinfo->ipv4_addresses;  | 
 | 110 	if (!list) { | 
 | 111 		return NULL;  | 
 | 112 	}  | 
 | 113   | 
 | 114 	if (!PyList_Check(list)) { | 
 | 115 		return NULL;  | 
 | 116 	}  | 
 | 117   | 
 | 118 	size = PyList_Size(list);  | 
 | 119 	if (size > 0) { | 
 | 120 		PyObject *item = PyList_GetItem(list, size - 1);  | 
 | 121 		if (Py_TYPE(item) == ðtool_netlink_ipv4_address_Type) { | 
 | 122 			return (PyNetlinkIPv4Address*)item;  | 
 | 123 		}  | 
 | 124 	}  | 
 | 125   | 
 | 126 	return NULL;  | 
 | 127 }  | 
 | 128   | 
 94 /**  | 129 /**  | 
 95  * ethtool.etherinfo function for retrieving data from a Python object.  | 130  * ethtool.etherinfo function for retrieving data from a Python object.  | 
 96  *  | 131  *  | 
 97  * @param self  | 132  * @param self  | 
 98  * @param attr_o  contains the object member request (which element to return)  | 133  * @param attr_o  contains the object member request (which element to return)  | 
 99  *  | 134  *  | 
100  * @return Returns a PyObject with the value requested on success, otherwise NULL  | 135  * @return Returns a PyObject with the value requested on success, otherwise NULL  | 
101  */  | 136  */  | 
102 PyObject *_ethtool_etherinfo_getter(etherinfo_py *self, PyObject *attr_o)  | 137 PyObject *_ethtool_etherinfo_getter(etherinfo_py *self, PyObject *attr_o)  | 
103 { | 138 { | 
104 	PyObject *ret;  |  | 
105 	char *attr = PyString_AsString(attr_o);  | 139 	char *attr = PyString_AsString(attr_o);  | 
 | 140 	PyNetlinkIPv4Address *py_addr;  | 
106   | 141   | 
107 	if( !self || !self->data ) { | 142 	if( !self || !self->data ) { | 
108 		PyErr_SetString(PyExc_AttributeError, "No data available");  | 143 		PyErr_SetString(PyExc_AttributeError, "No data available");  | 
109 		return NULL;  | 144 		return NULL;  | 
110 	}  | 145 	}  | 
111   | 146   | 
112 	if( strcmp(attr, "device") == 0 ) { | 147 	if( strcmp(attr, "device") == 0 ) { | 
113 		ret = RETURN_STRING(self->data->ethinfo->device);  | 148 		return RETURN_STRING(self->data->ethinfo->device);  | 
114 	} else if( strcmp(attr, "mac_address") == 0 ) { | 149 	} else if( strcmp(attr, "mac_address") == 0 ) { | 
115 		get_etherinfo(self->data, NLQRY_LINK);  | 150 		get_etherinfo(self->data, NLQRY_LINK);  | 
116 		ret = RETURN_STRING(self->data->ethinfo->hwaddress);  | 151 		return RETURN_STRING(self->data->ethinfo->hwaddress);  | 
117 	} else if( strcmp(attr, "ipv4_address") == 0 ) { | 152 	} else if( strcmp(attr, "ipv4_address") == 0 ) { | 
118 		get_etherinfo(self->data, NLQRY_ADDR);  | 153 		get_etherinfo(self->data, NLQRY_ADDR);  | 
119 		ret = RETURN_STRING(self->data->ethinfo->ipv4_address);  | 154 		/* For compatiblity with old approach, return last IPv4 address: */  | 
 | 155 		py_addr = get_last_address(self);  | 
 | 156 		if (py_addr) { | 
 | 157 		  if (py_addr->ipv4_address) { | 
 | 158 		      Py_INCREF(py_addr->ipv4_address);  | 
 | 159 		      return py_addr->ipv4_address;  | 
 | 160 		  }  | 
 | 161 		}  | 
 | 162 		Py_RETURN_NONE;  | 
120 	} else if( strcmp(attr, "ipv4_netmask") == 0 ) { | 163 	} else if( strcmp(attr, "ipv4_netmask") == 0 ) { | 
121 		get_etherinfo(self->data, NLQRY_ADDR);  | 164 		get_etherinfo(self->data, NLQRY_ADDR);  | 
122 		ret = PyInt_FromLong(self->data->ethinfo->ipv4_netmask);  | 165 		py_addr = get_last_address(self);  | 
 | 166 		if (py_addr) { | 
 | 167 		  return PyInt_FromLong(py_addr->ipv4_netmask);  | 
 | 168 		}  | 
 | 169 		return PyInt_FromLong(0);  | 
123 	} else if( strcmp(attr, "ipv4_broadcast") == 0 ) { | 170 	} else if( strcmp(attr, "ipv4_broadcast") == 0 ) { | 
124 		get_etherinfo(self->data, NLQRY_ADDR);  | 171 		get_etherinfo(self->data, NLQRY_ADDR);  | 
125 		ret = RETURN_STRING(self->data->ethinfo->ipv4_broadcast);  | 172 		py_addr = get_last_address(self);  | 
 | 173 		if (py_addr) { | 
 | 174 		  if (py_addr->ipv4_broadcast) { | 
 | 175 		      Py_INCREF(py_addr->ipv4_broadcast);  | 
 | 176 		      return py_addr->ipv4_broadcast;  | 
 | 177 		  }  | 
 | 178 		}  | 
 | 179 		Py_RETURN_NONE;  | 
126 	} else { | 180 	} else { | 
127 		ret = PyObject_GenericGetAttr((PyObject *)self, attr_o);  | 181 		return PyObject_GenericGetAttr((PyObject *)self, attr_o);  | 
128 	}  | 182 	}  | 
129   |  | 
130 	return ret;  |  | 
131 }  | 183 }    ob_refcnt of '*py_addr' is 1 too high    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
132   | 184   | 
133 /**  | 185 /**  | 
134  * ethtool.etherinfo function for setting a value to a object member.  This feature is  | 186  * ethtool.etherinfo function for setting a value to a object member.  This feature is  | 
135  * disabled by always returning -1, as the values are read-only by the user.  | 187  * disabled by always returning -1, as the values are read-only by the user.  | 
136  *  | 188  *  | 
137  * @param self  | 189  * @param self  | 
138  * @param attr_o  | 190  * @param attr_o  | 
139  * @param val_o  | 191  * @param val_o  | 
140  *  | 192  *  | 
141  * @return Returns always -1 (failure).  | 193  * @return Returns always -1 (failure).  | 
142  */  | 194  */  | 
143 int _ethtool_etherinfo_setter(etherinfo_py *self, PyObject *attr_o, PyObject *val_o)  | 195 int _ethtool_etherinfo_setter(etherinfo_py *self, PyObject *attr_o, PyObject *val_o)  | 
144 { | 196 { | 
145 	PyErr_SetString(PyExc_AttributeError, "etherinfo member values are read-only.");  | 197 	PyErr_SetString(PyExc_AttributeError, "etherinfo member values are read-only.");  | 
146 	return -1;  | 198 	return -1;  | 
147 }  | 199 }  | 
148   | 200   | 
149   | 201   | 
150 /**  | 202 /**  | 
151  * Creates a human readable format of the information when object is being treated as a string  | 203  * Creates a human readable format of the information when object is being treated as a string  | 
152  *  | 204  *  | 
153  * @param self  | 205  * @param self  | 
154  *  | 206  *  | 
155  * @return Returns a PyObject with a string with all of the information  | 207  * @return Returns a PyObject with a string with all of the information  | 
156  */  | 208  */  | 
157 PyObject *_ethtool_etherinfo_str(etherinfo_py *self)  | 209 PyObject *_ethtool_etherinfo_str(etherinfo_py *self)  | 
158 { | 210 { | 
159 	PyObject *ret = NULL;  | 211 	PyObject *ret = NULL;  | 
160   | 212   | 
161 	if( !self || !self->data || !self->data->nlc || !self->data->ethinfo ) { | 213 	if( !self || !self->data || !self->data->nlc || !self->data->ethinfo ) { | 
162 		PyErr_SetString(PyExc_AttributeError, "No data available");  | 214 		PyErr_SetString(PyExc_AttributeError, "No data available");  | 
163 		return NULL;  | 215 		return NULL;  | 
164 	}  | 216 	}  | 
165   | 217   | 
166 	get_etherinfo(self->data, NLQRY_LINK);  | 218 	get_etherinfo(self->data, NLQRY_LINK);  | 
167 	get_etherinfo(self->data, NLQRY_ADDR);  | 219 	get_etherinfo(self->data, NLQRY_ADDR);  | 
168   | 220   | 
169 	ret = PyString_FromFormat("Device %s:\n", self->data->ethinfo->device); | 221 	ret = PyString_FromFormat("Device %s:\n", self->data->ethinfo->device); | 
170 	if( self->data->ethinfo->hwaddress ) { | 222 	if( self->data->ethinfo->hwaddress ) { | 
171 		PyObject *tmp = PyString_FromFormat("\tMAC address: %s\n", self->data->ethinfo->hwaddress); | 223 		PyObject *tmp = PyString_FromFormat("\tMAC address: %s\n", self->data->ethinfo->hwaddress); | 
172 		PyString_Concat(&ret, tmp);  | 224 		PyString_Concat(&ret, tmp);  | 
173 		Py_DECREF(tmp);  | 225 		Py_DECREF(tmp);  | 
174 	}  | 226 	}  | 
175   | 227   | 
176 	if( self->data->ethinfo->ipv4_address ) { | 228 	if( self->data->ethinfo->ipv4_addresses ) { | 
177 		PyObject *tmp = PyString_FromFormat("\tIPv4 address: %s/%i", | 229                Py_ssize_t i;  | 
178 						   self->data->ethinfo->ipv4_address,  | 230                for (i = 0; i < PyList_Size(self->data->ethinfo->ipv4_addresses); i++) { | 
179 						   self->data->ethinfo->ipv4_netmask);  | 231                        PyNetlinkIPv4Address *py_addr = (PyNetlinkIPv4Address *)PyList_GetItem(self->data->ethinfo->ipv4_addresses, i);  | 
180 		if( self->data->ethinfo->ipv4_broadcast ) { | 232                        PyObject *tmp = PyString_FromFormat("\tIPv4 address: "); | 
181 			PyObject *tmp2 = PyString_FromFormat("	  Broadcast: %s", | 233                        PyString_Concat(&tmp, py_addr->ipv4_address);  | 
182 							     self->data->ethinfo->ipv4_broadcast);  | 234                        PyString_ConcatAndDel(&tmp, PyString_FromFormat("/%d", py_addr->ipv4_netmask)); | 
183 			PyString_Concat(&tmp, tmp2);  | 235                        if (py_addr->ipv4_broadcast ) { | 
184 			Py_DECREF(tmp2);  | 236                                 PyString_ConcatAndDel(&tmp,  | 
185 		}  | 237                                                       PyString_FromString("	  Broadcast: ")); | 
186 		PyString_Concat(&tmp, PyString_FromString("\n")); | 238                                 PyString_Concat(&tmp, py_addr->ipv4_broadcast);  | 
187 		PyString_Concat(&ret, tmp);  | 239                        }  | 
188 		Py_DECREF(tmp);  | 240                        PyString_ConcatAndDel(&tmp, PyString_FromString("\n")); | 
 | 241                        PyString_ConcatAndDel(&ret, tmp);  | 
 | 242                }  | 
189 	}  | 243 	}  | 
190   | 244   | 
191 	if( self->data->ethinfo->ipv6_addresses ) { | 245 	if( self->data->ethinfo->ipv6_addresses ) { | 
192 		struct ipv6address *ipv6 = self->data->ethinfo->ipv6_addresses;  | 246 		struct ipv6address *ipv6 = self->data->ethinfo->ipv6_addresses;  | 
193 		PyObject *tmp = PyString_FromFormat("\tIPv6 addresses:\n"); | 247 		PyObject *tmp = PyString_FromFormat("\tIPv6 addresses:\n"); | 
194 		PyString_Concat(&ret, tmp);  | 248 		PyString_Concat(&ret, tmp);  | 
195 		Py_DECREF(tmp);  | 249 		Py_DECREF(tmp);  | 
196 		for( ; ipv6; ipv6 = ipv6->next) { | 250 		for( ; ipv6; ipv6 = ipv6->next) { | 
197 			char scope[66];  | 251 			char scope[66];  | 
198   | 252   | 
199 			rtnl_scope2str(ipv6->scope, scope, 64);  | 253 			rtnl_scope2str(ipv6->scope, scope, 64);  | 
200 			PyObject *addr = PyString_FromFormat("\t		[%s] %s/%i\n", | 254 			PyObject *addr = PyString_FromFormat("\t		[%s] %s/%i\n", | 
201 							     scope, ipv6->address, ipv6->netmask);  | 255 							     scope, ipv6->address, ipv6->netmask);  | 
202 			PyString_Concat(&ret, addr);  | 256 			PyString_Concat(&ret, addr);  | 
203 			Py_DECREF(addr);    dereferencing NULL (addr->ob_refcnt) at python-ethtool/etherinfo_obj.c:203    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 257 			Py_DECREF(addr);    dereferencing NULL (addr->ob_refcnt) at python-ethtool/etherinfo_obj.c:257    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
204 		}  | 258 		}  | 
205 	}  | 259 	}  | 
 | 260 	return ret;  | 
 | 261 }  | 
 | 262   | 
 | 263 static PyObject *  | 
 | 264 _ethtool_etherinfo_get_ipv4_addresses(etherinfo_py *self, PyObject *notused) { | 
 | 265 	PyObject *ret;  | 
 | 266   | 
 | 267 	if( !self || !self->data ) { | 
 | 268 		PyErr_SetString(PyExc_AttributeError, "No data available");  | 
 | 269 		return NULL;  | 
 | 270 	}  | 
 | 271   | 
 | 272 	get_etherinfo(self->data, NLQRY_ADDR);  | 
 | 273   | 
 | 274 	/* Transfer ownership of reference: */  | 
 | 275 	ret = self->data->ethinfo->ipv4_addresses;  | 
 | 276 	self->data->ethinfo->ipv4_addresses = NULL;  | 
 | 277   | 
206 	return ret;  | 278 	return ret;  | 
207 }    ob_refcnt of PyStringObject is 1 too high    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 279 }  | 
208   | 280   | 
209   | 281   | 
210 /**  | 282 /**  | 
211  * Returns a tuple list of ethertool.etherinfo_ipv6addr objects, containing configured  | 283  * Returns a tuple list of ethertool.etherinfo_ipv6addr objects, containing configured  | 
212  * IPv6 addresses  | 284  * IPv6 addresses  | 
213  *  | 285  *  | 
214  * @param self  | 286  * @param self  | 
215  * @param notused  | 287  * @param notused  | 
216  *  | 288  *  | 
217  * @return Returns a Python tuple list of ethertool.etherinfo_ipv6addr objects  | 289  * @return Returns a Python tuple list of ethertool.etherinfo_ipv6addr objects  | 
218  */  | 290  */  | 
219 PyObject * _ethtool_etherinfo_get_ipv6_addresses(etherinfo_py *self, PyObject *notused) { | 291 PyObject * _ethtool_etherinfo_get_ipv6_addresses(etherinfo_py *self, PyObject *notused) { | 
220 	PyObject *ret;  | 292 	PyObject *ret;  | 
221 	struct ipv6address *ipv6 = NULL;  | 293 	struct ipv6address *ipv6 = NULL;  | 
222 	int i = 0;  | 294 	int i = 0;  | 
223   | 295   | 
224 	if( !self || !self->data ) { | 296 	if( !self || !self->data ) { | 
225 		PyErr_SetString(PyExc_AttributeError, "No data available");  | 297 		PyErr_SetString(PyExc_AttributeError, "No data available");  | 
226 		return NULL;  | 298 		return NULL;  | 
227 	}  | 299 	}  | 
228   | 300   | 
229 	get_etherinfo(self->data, NLQRY_ADDR);  | 301 	get_etherinfo(self->data, NLQRY_ADDR);  | 
230 	ipv6 = self->data->ethinfo->ipv6_addresses;  | 302 	ipv6 = self->data->ethinfo->ipv6_addresses;  | 
231 	ret = PyTuple_New(1);  | 303 	ret = PyTuple_New(1);  | 
232 	if( !ret ) { | 304 	if( !ret ) { | 
233 		PyErr_SetString(PyExc_MemoryError,  | 305 		PyErr_SetString(PyExc_MemoryError,  | 
234 				"[INTERNAL] Failed to allocate tuple list for "  | 306 				"[INTERNAL] Failed to allocate tuple list for "  | 
235 				"IPv6 address objects");  | 307 				"IPv6 address objects");  | 
236 		return NULL;  | 308 		return NULL;  | 
237 	}  | 309 	}  | 
238 	while( ipv6 ) { | 310 	while( ipv6 ) { | 
239 		PyObject *ipv6_pyobj = NULL, *ipv6_pydata = NULL, *args = NULL;  | 311 		PyObject *ipv6_pyobj = NULL, *ipv6_pydata = NULL, *args = NULL;  | 
240 		struct ipv6address *next = ipv6->next;  | 312 		struct ipv6address *next = ipv6->next;  | 
241   | 313   | 
242 		ipv6->next = NULL;  | 314 		ipv6->next = NULL;  | 
243 		ipv6_pydata = PyCObject_FromVoidPtr(ipv6, NULL);  | 315 		ipv6_pydata = PyCObject_FromVoidPtr(ipv6, NULL);  | 
244 		if( !ipv6_pydata ) { | 316 		if( !ipv6_pydata ) { | 
245 			PyErr_SetString(PyExc_MemoryError,  | 317 			PyErr_SetString(PyExc_MemoryError,  | 
246 					"[INTERNAL] Failed to create python object "  | 318 					"[INTERNAL] Failed to create python object "  | 
247 					"containing IPv6 address");  | 319 					"containing IPv6 address");  | 
248 			return NULL;  | 320 			return NULL;  | 
249 		}  | 321 		}  | 
250 		args = PyTuple_New(1);  | 322 		args = PyTuple_New(1);  | 
251 		if( !args ) { | 323 		if( !args ) { | 
252 			PyErr_SetString(PyExc_MemoryError,  | 324 			PyErr_SetString(PyExc_MemoryError,  | 
253 					"[INTERNAL] Failed to allocate argument list "  | 325 					"[INTERNAL] Failed to allocate argument list "  | 
254 					"a new IPv6 address object");  | 326 					"a new IPv6 address object");  | 
255 			return NULL;  | 327 			return NULL;  | 
256 		}  | 328 		}  | 
257 		PyTuple_SetItem(args, 0, ipv6_pydata);  | 329 		PyTuple_SetItem(args, 0, ipv6_pydata);  | 
258 		ipv6_pyobj = PyObject_CallObject((PyObject *)ðtool_etherinfoIPv6Type, args);  | 330 		ipv6_pyobj = PyObject_CallObject((PyObject *)ðtool_etherinfoIPv6Type, args);  | 
259 		Py_DECREF(args);  | 331 		Py_DECREF(args);  | 
260 		if( ipv6_pyobj ) { | 332 		if( ipv6_pyobj ) { | 
261 			PyTuple_SetItem(ret, i++, ipv6_pyobj);  | 333 			PyTuple_SetItem(ret, i++, ipv6_pyobj);  | 
262 			_PyTuple_Resize(&ret, i+1);  | 334 			_PyTuple_Resize(&ret, i+1);  | 
263 		} else { | 335 		} else { | 
264 			PyErr_SetString(PyExc_RuntimeError,  | 336 			PyErr_SetString(PyExc_RuntimeError,  | 
265 					"[INTERNAL] Failed to initialise the new "  | 337 					"[INTERNAL] Failed to initialise the new "  | 
266 					"IPv6 address object");  | 338 					"IPv6 address object");  | 
267 			return NULL;  | 339 			return NULL;  | 
268 		}  | 340 		}  | 
269 		ipv6 = next;  | 341 		ipv6 = next;  | 
270 	}  | 342 	}  | 
271 	_PyTuple_Resize(&ret, i);  | 343 	_PyTuple_Resize(&ret, i);  | 
272 	self->data->ethinfo->ipv6_addresses = NULL;  | 344 	self->data->ethinfo->ipv6_addresses = NULL;  | 
273 	return ret;  | 345 	return ret;  | 
274 }    ob_refcnt of '*ret' is 1 too high    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)     ob_refcnt of '*ipv6_pydata' is 1 too high    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)     ob_refcnt of '*ret.2' is 1 too high    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 346 }    ob_refcnt of '*ipv6_pydata' is 1 too high    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)     ob_refcnt of '*ret.2' is 1 too high    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
275   | 347   | 
276   | 348   | 
277 /**  | 349 /**  | 
278  * Defines all available methods in the ethtool.etherinfo class  | 350  * Defines all available methods in the ethtool.etherinfo class  | 
279  *  | 351  *  | 
280  */  | 352  */  | 
281 static PyMethodDef _ethtool_etherinfo_methods[] = { | 353 static PyMethodDef _ethtool_etherinfo_methods[] = { | 
282 	{"get_ipv6_addresses", _ethtool_etherinfo_get_ipv6_addresses, METH_NOARGS, | 354 	{"get_ipv4_addresses", (PyCFunction)_ethtool_etherinfo_get_ipv4_addresses, METH_NOARGS, | 
 | 355 	 "Retrieve configured IPv4 addresses.  Returns a list of NetlinkIP4Address objects"},  | 
 | 356 	{"get_ipv6_addresses", (PyCFunction)_ethtool_etherinfo_get_ipv6_addresses, METH_NOARGS, | 
283 	 "Retrieve configured IPv6 addresses.  Returns a tuple list of etherinfo_ipv6addr objects"},  | 357 	 "Retrieve configured IPv6 addresses.  Returns a tuple list of etherinfo_ipv6addr objects"},  | 
284 	{NULL}  /**< No methods defined */ | 358 	{NULL}  /**< No methods defined */ | 
285 };  |  | 
286   |  | 
287 /**  |  | 
288  * Defines all accessible object members  |  | 
289  *  |  | 
290  */  |  | 
291 static PyMemberDef _ethtool_etherinfo_members[] = { |  | 
292     {"device", T_OBJECT_EX, offsetof(etherinfo_py, data), 0, |  | 
293      "Device name of the interface"},  |  | 
294     {"mac_address", T_OBJECT_EX, offsetof(etherinfo_py, data), 0, |  | 
295      "MAC address / hardware address of the interface"},  |  | 
296     {"ipv4_address", T_OBJECT_EX, offsetof(etherinfo_py, data), 0, |  | 
297      "IPv4 address"},  |  | 
298     {"ipv4_netmask", T_INT, offsetof(etherinfo_py, data), 0, |  | 
299      "IPv4 netmask in bits"},  |  | 
300     {"ipv4_broadcast", T_OBJECT_EX, offsetof(etherinfo_py, data), 0, |  | 
301      "IPv4 broadcast address"},  |  | 
302     {NULL}  /* End of member list */ |  | 
303 };  | 359 };  | 
304   | 360   | 
305 /**  | 361 /**  | 
306  * Definition of the functions a Python class/object requires.  | 362  * Definition of the functions a Python class/object requires.  | 
307  *  | 363  *  | 
308  */  | 364  */  | 
309 PyTypeObject ethtool_etherinfoType = { | 365 PyTypeObject ethtool_etherinfoType = { | 
310     PyObject_HEAD_INIT(NULL)  | 366     PyObject_HEAD_INIT(NULL)  | 
311     0,                         /*ob_size*/  | 367     0,                         /*ob_size*/  | 
312     "ethtool.etherinfo",       /*tp_name*/  | 368     "ethtool.etherinfo",       /*tp_name*/  | 
313     sizeof(etherinfo_py),      /*tp_basicsize*/  | 369     sizeof(etherinfo_py),      /*tp_basicsize*/  | 
314     0,                         /*tp_itemsize*/  | 370     0,                         /*tp_itemsize*/  | 
315     (destructor)_ethtool_etherinfo_dealloc,/*tp_dealloc*/  | 371     (destructor)_ethtool_etherinfo_dealloc,/*tp_dealloc*/  | 
316     0,                         /*tp_print*/  | 372     0,                         /*tp_print*/  | 
317     0,                         /*tp_getattr*/  | 373     0,                         /*tp_getattr*/  | 
318     0,                         /*tp_setattr*/  | 374     0,                         /*tp_setattr*/  | 
319     0,                         /*tp_compare*/  | 375     0,                         /*tp_compare*/  | 
320     0,                         /*tp_repr*/  | 376     0,                         /*tp_repr*/  | 
321     0,                         /*tp_as_number*/  | 377     0,                         /*tp_as_number*/  | 
322     0,                         /*tp_as_sequence*/  | 378     0,                         /*tp_as_sequence*/  | 
323     0,                         /*tp_as_mapping*/  | 379     0,                         /*tp_as_mapping*/  | 
324     0,                         /*tp_hash */  | 380     0,                         /*tp_hash */  | 
325     0,                         /*tp_call*/  | 381     0,                         /*tp_call*/  | 
326     (reprfunc)_ethtool_etherinfo_str,        /*tp_str*/  | 382     (reprfunc)_ethtool_etherinfo_str,        /*tp_str*/  | 
327     (getattrofunc)_ethtool_etherinfo_getter, /*tp_getattro*/  | 383     (getattrofunc)_ethtool_etherinfo_getter, /*tp_getattro*/  | 
328     (setattrofunc)_ethtool_etherinfo_setter, /*tp_setattro*/  | 384     (setattrofunc)_ethtool_etherinfo_setter, /*tp_setattro*/  | 
329     0,                         /*tp_as_buffer*/  | 385     0,                         /*tp_as_buffer*/  | 
330     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/  | 386     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/  | 
331     "Contains information about a specific ethernet device", /* tp_doc */  | 387     "Contains information about a specific ethernet device", /* tp_doc */  | 
332     0,		               /* tp_traverse */  | 388     0,		               /* tp_traverse */  | 
333     0,		               /* tp_clear */  | 389     0,		               /* tp_clear */  | 
334     0,		               /* tp_richcompare */  | 390     0,		               /* tp_richcompare */  | 
335     0,		               /* tp_weaklistoffset */  | 391     0,		               /* tp_weaklistoffset */  | 
336     0,		               /* tp_iter */  | 392     0,		               /* tp_iter */  | 
337     0,		               /* tp_iternext */  | 393     0,		               /* tp_iternext */  | 
338     _ethtool_etherinfo_methods,            /* tp_methods */  | 394     _ethtool_etherinfo_methods,            /* tp_methods */  | 
339     _ethtool_etherinfo_members,            /* tp_members */  | 395     0,                         /* tp_members */  | 
340     0,                         /* tp_getset */  | 396     0,                         /* tp_getset */  | 
341     0,                         /* tp_base */  | 397     0,                         /* tp_base */  | 
342     0,                         /* tp_dict */  | 398     0,                         /* tp_dict */  | 
343     0,                         /* tp_descr_get */  | 399     0,                         /* tp_descr_get */  | 
344     0,                         /* tp_descr_set */  | 400     0,                         /* tp_descr_set */  | 
345     0,                         /* tp_dictoffset */  | 401     0,                         /* tp_dictoffset */  | 
346     (initproc)_ethtool_etherinfo_init,     /* tp_init */  | 402     (initproc)_ethtool_etherinfo_init,     /* tp_init */  | 
347     0,                         /* tp_alloc */  | 403     0,                         /* tp_alloc */  | 
348     _ethtool_etherinfo_new,                /* tp_new */  | 404     _ethtool_etherinfo_new,                /* tp_new */  | 
349 };  | 405 };  | 
  | 
  | 
  | 
  | 
   2  * Copyright (C) 2008-2011 Red Hat Inc.  |    2  * Copyright (C) 2008-2011 Red Hat Inc.  | 
   3  *  |    3  *  | 
   4  * Arnaldo Carvalho de Melo <acme@redhat.com>  |    4  * Arnaldo Carvalho de Melo <acme@redhat.com>  | 
   5  * David Sommerseth <davids@redhat.com>  |    5  * David Sommerseth <davids@redhat.com>  | 
   6  *  |    6  *  | 
   7  * First bits from a Red Hat config tool by Harald Hoyer.  |    7  * First bits from a Red Hat config tool by Harald Hoyer.  | 
   8  *  |    8  *  | 
   9  * This application is free software; you can redistribute it and/or modify it  |    9  * This application is free software; you can redistribute it and/or modify it  | 
  10  * under the terms of the GNU General Public License as published by the Free  |   10  * under the terms of the GNU General Public License as published by the Free  | 
  11  * Software Foundation; version 2.  |   11  * Software Foundation; version 2.  | 
  12  *  |   12  *  | 
  13  * This application is distributed in the hope that it will be useful,  |   13  * This application is distributed in the hope that it will be useful,  | 
  14  * but WITHOUT ANY WARRANTY; without even the implied warranty of  |   14  * but WITHOUT ANY WARRANTY; without even the implied warranty of  | 
  15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  |   15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  | 
  16  * General Public License for more details.  |   16  * General Public License for more details.  | 
  17  */  |   17  */  | 
  18 #include <Python.h>  |   18 #include <Python.h>  | 
  19   |   19   | 
  20 #include <errno.h>  |   20 #include <errno.h>  | 
  21 #include <stddef.h>  |   21 #include <stddef.h>  | 
  22 #include <stdint.h>  |   22 #include <stdint.h>  | 
  23 #include <unistd.h>  |   23 #include <unistd.h>  | 
  24 #include <sys/socket.h>  |   24 #include <sys/socket.h>  | 
  25 #include <net/if.h>  |   25 #include <net/if.h>  | 
  26 #include <sys/socket.h>  |   26 #include <sys/socket.h>  | 
  27 #include <sys/ioctl.h>  |   27 #include <sys/ioctl.h>  | 
  28 #include <sys/types.h>  |   28 #include <sys/types.h>  | 
  29   |   29   | 
  30 #include "etherinfo_struct.h"  |   30 #include "etherinfo_struct.h"  | 
  31 #include "etherinfo_obj.h"  |   31 #include "etherinfo_obj.h"  | 
  32 #include "etherinfo.h"  |   32 #include "etherinfo.h"  | 
  33   |   33   | 
  34 static struct nl_handle *nlconnection = NULL;  |   34 static struct nl_handle *nlconnection = NULL;  | 
  35 unsigned int nlconnection_users = 0;  /* How many NETLINK users are active? */  |   35 unsigned int nlconnection_users = 0;  /* How many NETLINK users are active? */  | 
  36 extern PyTypeObject ethtool_etherinfoType;  |   36 extern PyTypeObject ethtool_etherinfoType;  | 
  37 extern PyTypeObject ethtool_etherinfoIPv6Type;  |   37 extern PyTypeObject ethtool_etherinfoIPv6Type;  | 
  38   |   38   | 
  39 #ifndef IFF_DYNAMIC  |   39 #ifndef IFF_DYNAMIC  | 
  40 #define IFF_DYNAMIC     0x8000          /* dialup device with changing addresses*/  |   40 #define IFF_DYNAMIC     0x8000          /* dialup device with changing addresses*/  | 
  41 #endif  |   41 #endif  | 
  42   |   42   | 
  43 typedef unsigned long long u64;  |   43 typedef unsigned long long u64;  | 
  44 typedef __uint32_t u32;  |   44 typedef __uint32_t u32;  | 
  45 typedef __uint16_t u16;  |   45 typedef __uint16_t u16;  | 
  46 typedef __uint8_t u8;  |   46 typedef __uint8_t u8;  | 
  47   |   47   | 
  48 #include "ethtool-copy.h"  |   48 #include "ethtool-copy.h"  | 
  49 #include <linux/sockios.h> /* for SIOCETHTOOL */  |   49 #include <linux/sockios.h> /* for SIOCETHTOOL */  | 
  50   |   50   | 
  51 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))  |   51 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))  | 
  52   |   52   | 
  53 #define _PATH_PROCNET_DEV "/proc/net/dev"  |   53 #define _PATH_PROCNET_DEV "/proc/net/dev"  | 
  54   |   54   | 
  55 static PyObject *get_active_devices(PyObject *self __unused, PyObject *args __unused)  |   55 static PyObject *get_active_devices(PyObject *self __unused, PyObject *args __unused)  | 
  56 { |   56 { | 
  57 	PyObject *list;  |   57 	PyObject *list;  | 
  58 	int numreqs = 30;  |   58 	int numreqs = 30;  | 
  59 	struct ifconf ifc;  |   59 	struct ifconf ifc;  | 
  60 	struct ifreq *ifr;  |   60 	struct ifreq *ifr;  | 
  61 	int n;  |   61 	int n;  | 
  62   |   62   | 
  63 	/* SIOCGIFCONF currently seems to only work properly on AF_INET sockets  |   63 	/* SIOCGIFCONF currently seems to only work properly on AF_INET sockets  | 
  64 	   (as of 2.1.128) */  |   64 	   (as of 2.1.128) */  | 
  65 	/* Open control socket. */  |   65 	/* Open control socket. */  | 
  66 	int skfd = socket(AF_INET, SOCK_DGRAM, 0);  |   66 	int skfd = socket(AF_INET, SOCK_DGRAM, 0);  | 
  67   |   67   | 
  68 	if (skfd < 0) { |   68 	if (skfd < 0) { | 
  69 		PyErr_SetString(PyExc_OSError, strerror(errno));  |   69 		PyErr_SetString(PyExc_OSError, strerror(errno));  | 
  70 		return NULL;  |   70 		return NULL;  | 
  71 	}  |   71 	}  | 
  72   |   72   | 
  73 	ifc.ifc_buf = NULL;  |   73 	ifc.ifc_buf = NULL;  | 
  74 	for (;;) { |   74 	for (;;) { | 
  75 		ifc.ifc_len = sizeof(struct ifreq) * numreqs;  |   75 		ifc.ifc_len = sizeof(struct ifreq) * numreqs;  | 
  76 		ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);  |   76 		ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);  | 
  77   |   77   | 
  78 		if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { |   78 		if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { | 
  79 			PyErr_SetString(PyExc_OSError, strerror(errno));  |   79 			PyErr_SetString(PyExc_OSError, strerror(errno));  | 
  80 			free(ifc.ifc_buf);  |   80 			free(ifc.ifc_buf);  | 
  81 			close(skfd);  |   81 			close(skfd);  | 
  82 			return NULL;  |   82 			return NULL;  | 
  83 		}  |   83 		}  | 
  84   |   84   | 
  85 		if (ifc.ifc_len == (int)sizeof(struct ifreq) * numreqs) { |   85 		if (ifc.ifc_len == (int)sizeof(struct ifreq) * numreqs) { | 
  86 			/* assume it overflowed and try again */  |   86 			/* assume it overflowed and try again */  | 
  87 			numreqs += 10;  |   87 			numreqs += 10;  | 
  88 			continue;  |   88 			continue;  | 
  89 		}  |   89 		}  | 
  90 		break;  |   90 		break;  | 
  91 	}  |   91 	}  | 
  92   |   92   | 
  93 	list = PyList_New(0);  |   93 	list = PyList_New(0);  | 
  94 	ifr = ifc.ifc_req;  |   94 	ifr = ifc.ifc_req;  | 
  95 	for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) { |   95 	for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) { | 
  96 		if (!(ioctl(skfd, SIOCGIFFLAGS, ifr) < 0))  |   96 		if (!(ioctl(skfd, SIOCGIFFLAGS, ifr) < 0))  | 
  97 			if (ifr->ifr_flags & IFF_UP) { |   97 			if (ifr->ifr_flags & IFF_UP) { | 
  98 				PyObject *str = PyString_FromString(ifr->ifr_name);  |   98 				PyObject *str = PyString_FromString(ifr->ifr_name);  | 
  99 				PyList_Append(list, str);  |   99 				PyList_Append(list, str);  | 
 100 				Py_DECREF(str);  |  100 				Py_DECREF(str);  | 
 101 			}  |  101 			}  | 
 102 			ifr++;  |  102 			ifr++;  | 
 103 	}  |  103 	}  | 
 104   |  104   | 
 105 	free(ifc.ifc_buf);  |  105 	free(ifc.ifc_buf);  | 
 106 	close(skfd);  |  106 	close(skfd);  | 
 107   |  107   | 
 108 	return list;  |  108 	return list;  | 
 109 }  |  109 }  | 
 110   |  110   | 
 111 static PyObject *get_devices(PyObject *self __unused, PyObject *args __unused)  |  111 static PyObject *get_devices(PyObject *self __unused, PyObject *args __unused)  | 
 112 { |  112 { | 
 113 	char buffer[256];  |  113 	char buffer[256];  | 
 114 	char *ret;;    variable 'ret' set but not used    (emitted by gcc)   |  114 	char *ret;;    variable 'ret' set but not used    (emitted by gcc)   | 
 115 	PyObject *list = PyList_New(0);  |  115 	PyObject *list = PyList_New(0);  | 
 116 	FILE *fd = fopen(_PATH_PROCNET_DEV, "r");  |  116 	FILE *fd = fopen(_PATH_PROCNET_DEV, "r");  | 
 117   |  117   | 
 118 	if (fd == NULL) { |  118 	if (fd == NULL) { | 
 119 		PyErr_SetString(PyExc_OSError, strerror(errno));  |  119 		PyErr_SetString(PyExc_OSError, strerror(errno));  | 
 120 		return NULL;  |  120 		return NULL;  | 
 121 	}  |  121 	}  | 
 122 	/* skip over first two lines */  |  122 	/* skip over first two lines */  | 
 123 	ret = fgets(buffer, 256, fd); ret = fgets(buffer, 256, fd);    Value stored to 'ret' is never read    (emitted by clang-analyzer) TODO: a detailed trace is available in the data model (not yet rendered in this report)     Value stored to 'ret' is never read    (emitted by clang-analyzer) TODO: a detailed trace is available in the data model (not yet rendered in this report)   |  123 	ret = fgets(buffer, 256, fd); ret = fgets(buffer, 256, fd);    Value stored to 'ret' is never read    (emitted by clang-analyzer) TODO: a detailed trace is available in the data model (not yet rendered in this report)     Value stored to 'ret' is never read    (emitted by clang-analyzer) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
 124 	while (!feof(fd)) { |  124 	while (!feof(fd)) { | 
 125 		PyObject *str;  |  125 		PyObject *str;  | 
 126 		char *name = buffer;  |  126 		char *name = buffer;  | 
 127 		char *end = buffer;  |  127 		char *end = buffer;  | 
 128   |  128   | 
 129 		if (fgets(buffer, 256, fd) == NULL)  |  129 		if (fgets(buffer, 256, fd) == NULL)  | 
 130 			break;  |  130 			break;  | 
 131 		/* find colon */  |  131 		/* find colon */  | 
 132 		while (end && *end != ':')    Possible null pointer dereference: end - otherwise it is redundant to check it against null.    (emitted by cppcheck)   |  132 		while (*end && *end != ':')    comparison against uninitialized data (D.13623) at python-ethtool/ethtool.c:132    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
 133 			end++;  |  133 			end++;  | 
 134 		*end = 0; /* terminate where colon was */    Possible null pointer dereference: end - otherwise it is redundant to check it against null.    (emitted by cppcheck)   |  134 		*end = 0; /* terminate where colon was */  | 
 135 		while (*name == ' ')  |  135 		while (*name == ' ')  | 
 136 			name++; /* skip over leading whitespace if any */  |  136 			name++; /* skip over leading whitespace if any */  | 
 137   |  137   | 
 138 		str = PyString_FromString(name);  |  138 		str = PyString_FromString(name);  | 
 139 		PyList_Append(list, str);    calling PyList_Append with NULL as argument 1 (list) at python-ethtool/ethtool.c:139    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   |  139 		PyList_Append(list, str);  | 
 140 		Py_DECREF(str);    dereferencing NULL (str->ob_refcnt) at python-ethtool/ethtool.c:140    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   |  140 		Py_DECREF(str);  | 
 141 	}  |  141 	}  | 
 142 	fclose(fd);  |  142 	fclose(fd);  | 
 143 	return list;  |  143 	return list;  | 
 144 }    ob_refcnt of '*list' is 1 too high    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   |  144 }    ob_refcnt of '*list' is 1 too high    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
 145   |  145   | 
 146 static PyObject *get_hwaddress(PyObject *self __unused, PyObject *args)  |  146 static PyObject *get_hwaddress(PyObject *self __unused, PyObject *args)  | 
 147 { |  147 { | 
 148 	struct ifreq ifr;  |  148 	struct ifreq ifr;  | 
 149 	int fd, err;  |  149 	int fd, err;  | 
 150 	char *devname;  |  150 	const char *devname;  | 
 151 	char hwaddr[20];  |  151 	char hwaddr[20];  | 
 152   |  152   | 
 153 	if (!PyArg_ParseTuple(args, "s", &devname))    Mismatching type in call to PyArg_ParseTuple with format code "s"      argument 3 ("&devname") had type
    "char * *"
  but was expecting
    "const char * *"
  for format code "s"
    (emitted by cpychecker)   |  153 	if (!PyArg_ParseTuple(args, "s", &devname))  | 
 154 		return NULL;  |  154 		return NULL;  | 
 155   |  155   | 
 156 	/* Setup our request structure. */  |  156 	/* Setup our request structure. */  | 
 157 	memset(&ifr, 0, sizeof(ifr));  |  157 	memset(&ifr, 0, sizeof(ifr));  | 
 158 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  |  158 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  | 
 159 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  |  159 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  | 
 160   |  160   | 
 161 	/* Open control socket. */  |  161 	/* Open control socket. */  | 
 162 	fd = socket(AF_INET, SOCK_DGRAM, 0);  |  162 	fd = socket(AF_INET, SOCK_DGRAM, 0);  | 
 163 	if (fd < 0) { |  163 	if (fd < 0) { | 
 164 		PyErr_SetString(PyExc_OSError, strerror(errno));  |  164 		PyErr_SetString(PyExc_OSError, strerror(errno));  | 
 165 		return NULL;  |  165 		return NULL;  | 
 166 	}  |  166 	}  | 
 167   |  167   | 
 168 	/* Get current settings. */  |  168 	/* Get current settings. */  | 
 169 	err = ioctl(fd, SIOCGIFHWADDR, &ifr);  |  169 	err = ioctl(fd, SIOCGIFHWADDR, &ifr);  | 
 170 	if (err < 0) { |  170 	if (err < 0) { | 
 171 		char buf[2048];  |  171 		char buf[2048];  | 
 172 		int eno = errno;  |  172 		int eno = errno;  | 
 173   |  173   | 
 174 		snprintf(buf, sizeof(buf), "[Errno %d] %s", eno, strerror(eno));  |  174 		snprintf(buf, sizeof(buf), "[Errno %d] %s", eno, strerror(eno));  | 
 175 		PyErr_SetString(PyExc_IOError, buf);  |  175 		PyErr_SetString(PyExc_IOError, buf);  | 
 176 		close(fd);  |  176 		close(fd);  | 
 177 		return NULL;  |  177 		return NULL;  | 
 178 	}  |  178 	}  | 
 179   |  179   | 
 180 	close(fd);  |  180 	close(fd);  | 
 181   |  181   | 
 182 	sprintf(hwaddr, "%02x:%02x:%02x:%02x:%02x:%02x",  |  182 	sprintf(hwaddr, "%02x:%02x:%02x:%02x:%02x:%02x",  | 
 183 		(unsigned int)ifr.ifr_hwaddr.sa_data[0] % 256,  |  183 		(unsigned int)ifr.ifr_hwaddr.sa_data[0] % 256,  | 
 184 		(unsigned int)ifr.ifr_hwaddr.sa_data[1] % 256,  |  184 		(unsigned int)ifr.ifr_hwaddr.sa_data[1] % 256,  | 
 185 		(unsigned int)ifr.ifr_hwaddr.sa_data[2] % 256,  |  185 		(unsigned int)ifr.ifr_hwaddr.sa_data[2] % 256,  | 
 186 		(unsigned int)ifr.ifr_hwaddr.sa_data[3] % 256,  |  186 		(unsigned int)ifr.ifr_hwaddr.sa_data[3] % 256,  | 
 187 		(unsigned int)ifr.ifr_hwaddr.sa_data[4] % 256,  |  187 		(unsigned int)ifr.ifr_hwaddr.sa_data[4] % 256,  | 
 188 		(unsigned int)ifr.ifr_hwaddr.sa_data[5] % 256);  |  188 		(unsigned int)ifr.ifr_hwaddr.sa_data[5] % 256);  | 
 189   |  189   | 
 190 	return PyString_FromString(hwaddr);  |  190 	return PyString_FromString(hwaddr);  | 
 191 }  |  191 }  | 
 192   |  192   | 
 193 static PyObject *get_ipaddress(PyObject *self __unused, PyObject *args)  |  193 static PyObject *get_ipaddress(PyObject *self __unused, PyObject *args)  | 
 194 { |  194 { | 
 195 	struct ifreq ifr;  |  195 	struct ifreq ifr;  | 
 196 	int fd, err;  |  196 	int fd, err;  | 
 197 	char *devname;  |  197 	const char *devname;  | 
 198 	char ipaddr[20];  |  198 	char ipaddr[20];  | 
 199   |  199   | 
 200 	if (!PyArg_ParseTuple(args, "s", &devname))    Mismatching type in call to PyArg_ParseTuple with format code "s"      argument 3 ("&devname") had type
    "char * *"
  but was expecting
    "const char * *"
  for format code "s"
    (emitted by cpychecker)   |  200 	if (!PyArg_ParseTuple(args, "s", &devname))  | 
 201 		return NULL;  |  201 		return NULL;  | 
 202   |  202   | 
 203 	/* Setup our request structure. */  |  203 	/* Setup our request structure. */  | 
 204 	memset(&ifr, 0, sizeof(ifr));  |  204 	memset(&ifr, 0, sizeof(ifr));  | 
 205 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  |  205 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  | 
 206 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  |  206 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  | 
 207   |  207   | 
 208 	/* Open control socket. */  |  208 	/* Open control socket. */  | 
 209 	fd = socket(AF_INET, SOCK_DGRAM, 0);  |  209 	fd = socket(AF_INET, SOCK_DGRAM, 0);  | 
 210 	if (fd < 0) { |  210 	if (fd < 0) { | 
 211 		PyErr_SetString(PyExc_OSError, strerror(errno));  |  211 		PyErr_SetString(PyExc_OSError, strerror(errno));  | 
 212 		return NULL;  |  212 		return NULL;  | 
 213 	}  |  213 	}  | 
 214   |  214   | 
 215 	/* Get current settings. */  |  215 	/* Get current settings. */  | 
 216 	err = ioctl(fd, SIOCGIFADDR, &ifr);  |  216 	err = ioctl(fd, SIOCGIFADDR, &ifr);  | 
 217 	if (err < 0) { |  217 	if (err < 0) { | 
 218 		char buf[2048];  |  218 		char buf[2048];  | 
 219 		int eno = errno;  |  219 		int eno = errno;  | 
 220 		snprintf(buf, sizeof(buf), "[Errno %d] %s", eno, strerror(eno));  |  220 		snprintf(buf, sizeof(buf), "[Errno %d] %s", eno, strerror(eno));  | 
 221 		PyErr_SetString(PyExc_IOError, buf);  |  221 		PyErr_SetString(PyExc_IOError, buf);  | 
 222 		close(fd);  |  222 		close(fd);  | 
 223 		return NULL;  |  223 		return NULL;  | 
 224 	}  |  224 	}  | 
 225   |  225   | 
 226 	close(fd);  |  226 	close(fd);  | 
 227   |  227   | 
 228 	sprintf(ipaddr, "%u.%u.%u.%u",  |  228 	sprintf(ipaddr, "%u.%u.%u.%u",  | 
 229 		(unsigned int)ifr.ifr_addr.sa_data[2] % 256,  |  229 		(unsigned int)ifr.ifr_addr.sa_data[2] % 256,  | 
 230 		(unsigned int)ifr.ifr_addr.sa_data[3] % 256,  |  230 		(unsigned int)ifr.ifr_addr.sa_data[3] % 256,  | 
 231 		(unsigned int)ifr.ifr_addr.sa_data[4] % 256,  |  231 		(unsigned int)ifr.ifr_addr.sa_data[4] % 256,  | 
 232 		(unsigned int)ifr.ifr_addr.sa_data[5] % 256);  |  232 		(unsigned int)ifr.ifr_addr.sa_data[5] % 256);  | 
 233   |  233   | 
 234 	return PyString_FromString(ipaddr);  |  234 	return PyString_FromString(ipaddr);  | 
 235 }  |  235 }  | 
 236   |  236   | 
 237   |  237   | 
 238 /**  |  238 /**  | 
 239  * Retrieves the current information about all interfaces.  All interfaces will be  |  239  * Retrieves the current information about all interfaces.  All interfaces will be  | 
 240  * returned as a list of objects per interface.  |  240  * returned as a list of objects per interface.  | 
 241  *  |  241  *  | 
 242  * @param self Not used  |  242  * @param self Not used  | 
 243  * @param args Python arguments  |  243  * @param args Python arguments  | 
 244  *  |  244  *  | 
 245  * @return Python list of objects on success, otherwise NULL.  |  245  * @return Python list of objects on success, otherwise NULL.  | 
 246  */  |  246  */  | 
 247 static PyObject *get_interfaces_info(PyObject *self __unused, PyObject *args) { |  247 static PyObject *get_interfaces_info(PyObject *self __unused, PyObject *args) { | 
 248 	PyObject *devlist = NULL, *ethinf_py = NULL;  |  248 	PyObject *devlist = NULL, *ethinf_py = NULL;  | 
 249 	PyObject *inargs = NULL;  |  249 	PyObject *inargs = NULL;  | 
 250 	char **fetch_devs;  |  250 	char **fetch_devs = NULL;  | 
 251 	int i = 0, fetch_devs_len = 0;  |  251 	int i = 0, fetch_devs_len = 0;  | 
 252   |  252   | 
 253 	if (!PyArg_ParseTuple(args, "|O", &inargs)) { |  253 	if (!PyArg_ParseTuple(args, "|O", &inargs)) { | 
 254 		PyErr_SetString(PyExc_LookupError,  |  254 		PyErr_SetString(PyExc_LookupError,  | 
 255 				"Argument must be either a string, list or a tuple");  |  255 				"Argument must be either a string, list or a tuple");  | 
 256 		return NULL;  |  256 		return NULL;  | 
 257 	}  |  257 	}  | 
 258   |  258   | 
 259 	/* Parse input arguments if we got them */  |  259 	/* Parse input arguments if we got them */  | 
 260 	if( inargs != NULL ) { |  260 	if( inargs != NULL ) { | 
 261 		if( PyString_Check(inargs) ) { /* Input argument is just a string */ |  261 		if( PyString_Check(inargs) ) { /* Input argument is just a string */ | 
 262 			fetch_devs_len = 1;  |  262 			fetch_devs_len = 1;  | 
 263 			fetch_devs = calloc(1, sizeof(char *));  |  263 			fetch_devs = calloc(1, sizeof(char *));  | 
 264 			fetch_devs[0] = PyString_AsString(inargs);  |  264 			fetch_devs[0] = PyString_AsString(inargs);  | 
 265 		} else if( PyTuple_Check(inargs) ) { /* Input argument is a tuple list with devices */ |  265 		} else if( PyTuple_Check(inargs) ) { /* Input argument is a tuple list with devices */ | 
 266 			int j = 0;  |  266 			int j = 0;  | 
 267   |  267   | 
 268 			fetch_devs_len = PyTuple_Size(inargs);  |  268 			fetch_devs_len = PyTuple_Size(inargs);  | 
 269 			fetch_devs = calloc(fetch_devs_len+1, sizeof(char *));  |  269 			fetch_devs = calloc(fetch_devs_len+1, sizeof(char *));  | 
 270 			for( i = 0; i < fetch_devs_len; i++ ) { |  270 			for( i = 0; i < fetch_devs_len; i++ ) { | 
 271 				PyObject *elmt = PyTuple_GetItem(inargs, i);  |  271 				PyObject *elmt = PyTuple_GetItem(inargs, i);  | 
 272 				if( elmt && PyString_Check(elmt) ) { |  272 				if( elmt && PyString_Check(elmt) ) { | 
 273 					fetch_devs[j++] = PyString_AsString(elmt);  |  273 					fetch_devs[j++] = PyString_AsString(elmt);  | 
 274 				}  |  274 				}  | 
 275 			}  |  275 			}  | 
 276 			fetch_devs_len = j;  |  276 			fetch_devs_len = j;  | 
 277 		} else if( PyList_Check(inargs) ) { /* Input argument is a list with devices */ |  277 		} else if( PyList_Check(inargs) ) { /* Input argument is a list with devices */ | 
 278 			int j = 0;  |  278 			int j = 0;  | 
 279   |  279   | 
 280 			fetch_devs_len = PyList_Size(inargs);  |  280 			fetch_devs_len = PyList_Size(inargs);  | 
 281 			fetch_devs = calloc(fetch_devs_len+1, sizeof(char *));  |  281 			fetch_devs = calloc(fetch_devs_len+1, sizeof(char *));  | 
 282 			for( i = 0; i < fetch_devs_len; i++ ) { |  282 			for( i = 0; i < fetch_devs_len; i++ ) { | 
 283 				PyObject *elmt = PyList_GetItem(inargs, i);  |  283 				PyObject *elmt = PyList_GetItem(inargs, i);  | 
 284 				if( elmt && PyString_Check(elmt) ) { |  284 				if( elmt && PyString_Check(elmt) ) { | 
 285 					fetch_devs[j++] = PyString_AsString(elmt);  |  285 					fetch_devs[j++] = PyString_AsString(elmt);  | 
 286 				}  |  286 				}  | 
 287 			}  |  287 			}  | 
 288 			fetch_devs_len = j;  |  288 			fetch_devs_len = j;  | 
 289 		} else { |  289 		} else { | 
 290 			PyErr_SetString(PyExc_LookupError,  |  290 			PyErr_SetString(PyExc_LookupError,  | 
 291 					"Argument must be either a string, list or a tuple");  |  291 					"Argument must be either a string, list or a tuple");  | 
 292 			return NULL;  |  292 			return NULL;  | 
 293 		}  |  293 		}  | 
 294 	}  |  294 	}  | 
 295   |  295   | 
 296 	devlist = PyList_New(0);  |  296 	devlist = PyList_New(0);  | 
 297 	for( i = 0; i < fetch_devs_len; i++ ) { |  297 	for( i = 0; i < fetch_devs_len; i++ ) { | 
 298 		struct etherinfo_obj_data *objdata = NULL;  |  298 		struct etherinfo_obj_data *objdata = NULL;  | 
 299   |  299   | 
 300 		/* Allocate memory for data structures for each device */  |  300 		/* Allocate memory for data structures for each device */  | 
 301 		objdata = calloc(1, sizeof(struct etherinfo_obj_data));  |  301 		objdata = calloc(1, sizeof(struct etherinfo_obj_data));  | 
 302 		if( !objdata ) { |  302 		if( !objdata ) { | 
 303 			PyErr_SetString(PyExc_OSError, strerror(errno));  |  303 			PyErr_SetString(PyExc_OSError, strerror(errno));  | 
 |  304 			free(fetch_devs);  | 
 304 			return NULL;    Memory leak: fetch_devs    (emitted by cppcheck)   |  305 			return NULL;  | 
 305 		}  |  306 		}  | 
 306   |  307   | 
 307 		objdata->ethinfo = calloc(1, sizeof(struct etherinfo));  |  308 		objdata->ethinfo = calloc(1, sizeof(struct etherinfo));  | 
 308 		if( !objdata->ethinfo ) { |  309 		if( !objdata->ethinfo ) { | 
 309 			PyErr_SetString(PyExc_OSError, strerror(errno));  |  310 			PyErr_SetString(PyExc_OSError, strerror(errno));  | 
 |  311 			free(fetch_devs);  | 
 310 			return NULL;  |  312 			return NULL;  | 
 311 		}  |  313 		}  | 
 312   |  314   | 
 313 		/* Store the device name and a reference to the NETLINK connection for  |  315 		/* Store the device name and a reference to the NETLINK connection for  | 
 314 		 * objects to use when quering for device info  |  316 		 * objects to use when quering for device info  | 
 315 		 */  |  317 		 */  | 
 316 		objdata->ethinfo->device = strdup(fetch_devs[i]);  |  318 		objdata->ethinfo->device = strdup(fetch_devs[i]);  | 
 317 		objdata->ethinfo->index = -1;  |  319 		objdata->ethinfo->index = -1;  | 
 318 		objdata->nlc = &nlconnection;  |  320 		objdata->nlc = &nlconnection;  | 
 319 		objdata->nlc_users = &nlconnection_users;  |  321 		objdata->nlc_users = &nlconnection_users;  | 
 320   |  322   | 
 321 		/* Instantiate a new etherinfo object with the device information */  |  323 		/* Instantiate a new etherinfo object with the device information */  | 
 322 		ethinf_py = PyCObject_FromVoidPtr(objdata, NULL);  |  324 		ethinf_py = PyCObject_FromVoidPtr(objdata, NULL);  | 
 323 		if( ethinf_py ) { |  325 		if( ethinf_py ) { | 
 324 			/* Prepare the argument list for the object constructor */  |  326 			/* Prepare the argument list for the object constructor */  | 
 325 			PyObject *args = PyTuple_New(1);  |  327 			PyObject *args = PyTuple_New(1);  | 
 326 			PyTuple_SetItem(args, 0, ethinf_py);  |  328 			PyTuple_SetItem(args, 0, ethinf_py);    calling PyTuple_SetItem with NULL as argument 1 (args) at python-ethtool/ethtool.c:328    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
 327   |  329   | 
 328 			/* Create the object */  |  330 			/* Create the object */  | 
 329 			PyObject *dev = PyObject_CallObject((PyObject *)ðtool_etherinfoType, args);  |  331 			PyObject *dev = PyObject_CallObject((PyObject *)ðtool_etherinfoType, args);  | 
 330 			if( dev ) { |  332 			if( dev ) { | 
 331 				PyList_Append(devlist, dev);  |  333 				PyList_Append(devlist, dev);  | 
 332 				Py_DECREF(dev);  |  334 				Py_DECREF(dev);  | 
 333 			}  |  335 			}  | 
 334 			Py_DECREF(args);  |  336 			Py_DECREF(args);  | 
 335 		}  |  337 		}  | 
 336 	}  |  338 	}  | 
 337 	if( fetch_devs_len > 0 ) { |  339   | 
 338 		free(fetch_devs);  |  340 	free(fetch_devs);  | 
 339 	}  |  | 
 340   |  341   | 
 341 	return devlist;  |  342 	return devlist;  | 
 342 }  |  343 }  | 
 343   |  344   | 
 344   |  345   | 
 345 static PyObject *get_flags (PyObject *self __unused, PyObject *args)  |  346 static PyObject *get_flags (PyObject *self __unused, PyObject *args)  | 
 346 { |  347 { | 
 347 	struct ifreq ifr;  |  348 	struct ifreq ifr;  | 
 348 	char *devname;  |  349 	const char *devname;  | 
 349 	int fd, err;  |  350 	int fd, err;  | 
 350   |  351   | 
 351 	if (!PyArg_ParseTuple(args, "s", &devname))    Mismatching type in call to PyArg_ParseTuple with format code "s"      argument 3 ("&devname") had type
    "char * *"
  but was expecting
    "const char * *"
  for format code "s"
    (emitted by cpychecker)   |  352 	if (!PyArg_ParseTuple(args, "s", &devname))  | 
 352 		return NULL;  |  353 		return NULL;  | 
 353   |  354   | 
 354 	/* Setup our request structure. */  |  355 	/* Setup our request structure. */  | 
 355 	memset(&ifr, 0, sizeof(ifr));  |  356 	memset(&ifr, 0, sizeof(ifr));  | 
 356 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  |  357 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  | 
 357 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  |  358 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  | 
 358   |  359   | 
 359 	/* Open control socket. */  |  360 	/* Open control socket. */  | 
 360 	fd = socket(AF_INET, SOCK_DGRAM, 0);  |  361 	fd = socket(AF_INET, SOCK_DGRAM, 0);  | 
 361 	if (fd < 0) { |  362 	if (fd < 0) { | 
 362 		PyErr_SetString(PyExc_OSError, strerror(errno));  |  363 		PyErr_SetString(PyExc_OSError, strerror(errno));  | 
 363 		return NULL;  |  364 		return NULL;  | 
 364 	}  |  365 	}  | 
 365 	err = ioctl(fd, SIOCGIFFLAGS, &ifr);  |  366 	err = ioctl(fd, SIOCGIFFLAGS, &ifr);  | 
 366 	if(err < 0) { |  367 	if(err < 0) { | 
 367 		char buf[2048];  |  368 		char buf[2048];  | 
 368 		int eno = errno;  |  369 		int eno = errno;  | 
 369 		snprintf(buf, sizeof(buf), "[Errno %d] %s", eno, strerror(eno));  |  370 		snprintf(buf, sizeof(buf), "[Errno %d] %s", eno, strerror(eno));  | 
 370 		PyErr_SetString(PyExc_IOError, buf);  |  371 		PyErr_SetString(PyExc_IOError, buf);  | 
 371 		close(fd);  |  372 		close(fd);  | 
 372 		return NULL;  |  373 		return NULL;  | 
 373 	}  |  374 	}  | 
 374   |  375   | 
 375 	close(fd);  |  376 	close(fd);  | 
 376   |  377   | 
 377 	return Py_BuildValue("h", ifr.ifr_flags);   Mismatching type in call to Py_BuildValue with format code "h"      argument 2 ("D.13357") had type
    "int"
  but was expecting
    "short int"
  for format code "h"
    (emitted by cpychecker)   |  378 	return Py_BuildValue("h", ifr.ifr_flags);   Mismatching type in call to Py_BuildValue with format code "h"      argument 2 ("D.13370") had type
    "int"
  but was expecting
    "short int"
  for format code "h"
    (emitted by cpychecker)   | 
 378   |  379   | 
 379   |  380   | 
 380 }  |  381 }  | 
 381 static PyObject *get_netmask (PyObject *self __unused, PyObject *args)  |  382 static PyObject *get_netmask (PyObject *self __unused, PyObject *args)  | 
 382 { |  383 { | 
 383 	struct ifreq ifr;  |  384 	struct ifreq ifr;  | 
 384 	int fd, err;  |  385 	int fd, err;  | 
 385 	char *devname;  |  386 	const char *devname;  | 
 386 	char netmask[20];  |  387 	char netmask[20];  | 
 387   |  388   | 
 388 	if (!PyArg_ParseTuple(args, "s", &devname))    Mismatching type in call to PyArg_ParseTuple with format code "s"      argument 3 ("&devname") had type
    "char * *"
  but was expecting
    "const char * *"
  for format code "s"
    (emitted by cpychecker)   |  389 	if (!PyArg_ParseTuple(args, "s", &devname))  | 
 389 		return NULL;  |  390 		return NULL;  | 
 390   |  391   | 
 391 	/* Setup our request structure. */  |  392 	/* Setup our request structure. */  | 
 392 	memset(&ifr, 0, sizeof(ifr));  |  393 	memset(&ifr, 0, sizeof(ifr));  | 
 393 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  |  394 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  | 
 394 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  |  395 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  | 
 395   |  396   | 
 396 	/* Open control socket. */  |  397 	/* Open control socket. */  | 
 397 	fd = socket(AF_INET, SOCK_DGRAM, 0);  |  398 	fd = socket(AF_INET, SOCK_DGRAM, 0);  | 
 398 	if (fd < 0) { |  399 	if (fd < 0) { | 
 399 		PyErr_SetString(PyExc_OSError, strerror(errno));  |  400 		PyErr_SetString(PyExc_OSError, strerror(errno));  | 
 400 		return NULL;  |  401 		return NULL;  | 
 401 	}  |  402 	}  | 
 402   |  403   | 
 403 	/* Get current settings. */  |  404 	/* Get current settings. */  | 
 404 	err = ioctl(fd, SIOCGIFNETMASK, &ifr);  |  405 	err = ioctl(fd, SIOCGIFNETMASK, &ifr);  | 
 405 	if (err < 0) { |  406 	if (err < 0) { | 
 406 		char buf[2048];  |  407 		char buf[2048];  | 
 407 		int eno = errno;  |  408 		int eno = errno;  | 
 408 		snprintf(buf, sizeof(buf), "[Errno %d] %s", eno, strerror(eno));  |  409 		snprintf(buf, sizeof(buf), "[Errno %d] %s", eno, strerror(eno));  | 
 409 		PyErr_SetString(PyExc_IOError, buf);  |  410 		PyErr_SetString(PyExc_IOError, buf);  | 
 410 		close(fd);  |  411 		close(fd);  | 
 411 		return NULL;  |  412 		return NULL;  | 
 412 	}  |  413 	}  | 
 413   |  414   | 
 414 	close(fd);  |  415 	close(fd);  | 
 415   |  416   | 
 416 	sprintf(netmask, "%u.%u.%u.%u",  |  417 	sprintf(netmask, "%u.%u.%u.%u",  | 
 417 		(unsigned int)ifr.ifr_netmask.sa_data[2] % 256,  |  418 		(unsigned int)ifr.ifr_netmask.sa_data[2] % 256,  | 
 418 		(unsigned int)ifr.ifr_netmask.sa_data[3] % 256,  |  419 		(unsigned int)ifr.ifr_netmask.sa_data[3] % 256,  | 
 419 		(unsigned int)ifr.ifr_netmask.sa_data[4] % 256,  |  420 		(unsigned int)ifr.ifr_netmask.sa_data[4] % 256,  | 
 420 		(unsigned int)ifr.ifr_netmask.sa_data[5] % 256);  |  421 		(unsigned int)ifr.ifr_netmask.sa_data[5] % 256);  | 
 421   |  422   | 
 422 	return PyString_FromString(netmask);  |  423 	return PyString_FromString(netmask);  | 
 423 }  |  424 }  | 
 424   |  425   | 
 425 static PyObject *get_broadcast(PyObject *self __unused, PyObject *args)  |  426 static PyObject *get_broadcast(PyObject *self __unused, PyObject *args)  | 
 426 { |  427 { | 
 427 	struct ifreq ifr;  |  428 	struct ifreq ifr;  | 
 428 	int fd, err;  |  429 	int fd, err;  | 
 429 	char *devname;  |  430 	const char *devname;  | 
 430 	char broadcast[20];  |  431 	char broadcast[20];  | 
 431   |  432   | 
 432 	if (!PyArg_ParseTuple(args, "s", &devname))    Mismatching type in call to PyArg_ParseTuple with format code "s"      argument 3 ("&devname") had type
    "char * *"
  but was expecting
    "const char * *"
  for format code "s"
    (emitted by cpychecker)   |  433 	if (!PyArg_ParseTuple(args, "s", &devname))  | 
 433 		return NULL;  |  434 		return NULL;  | 
 434   |  435   | 
 435 	/* Setup our request structure. */  |  436 	/* Setup our request structure. */  | 
 436 	memset(&ifr, 0, sizeof(ifr));  |  437 	memset(&ifr, 0, sizeof(ifr));  | 
 437 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  |  438 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  | 
 438 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  |  439 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  | 
 439   |  440   | 
 440 	/* Open control socket. */  |  441 	/* Open control socket. */  | 
 441 	fd = socket(AF_INET, SOCK_DGRAM, 0);  |  442 	fd = socket(AF_INET, SOCK_DGRAM, 0);  | 
 442 	if (fd < 0) { |  443 	if (fd < 0) { | 
 443 		PyErr_SetString(PyExc_OSError, strerror(errno));  |  444 		PyErr_SetString(PyExc_OSError, strerror(errno));  | 
 444 		return NULL;  |  445 		return NULL;  | 
 445 	}  |  446 	}  | 
 446   |  447   | 
 447 	/* Get current settings. */  |  448 	/* Get current settings. */  | 
 448 	err = ioctl(fd, SIOCGIFBRDADDR, &ifr);  |  449 	err = ioctl(fd, SIOCGIFBRDADDR, &ifr);  | 
 449 	if (err < 0) { |  450 	if (err < 0) { | 
 450 		char buf[2048];  |  451 		char buf[2048];  | 
 451 		int eno = errno;  |  452 		int eno = errno;  | 
 452 		snprintf(buf, sizeof(buf), "[Errno %d] %s", eno, strerror(eno));  |  453 		snprintf(buf, sizeof(buf), "[Errno %d] %s", eno, strerror(eno));  | 
 453 		PyErr_SetString(PyExc_IOError, buf);  |  454 		PyErr_SetString(PyExc_IOError, buf);  | 
 454 		close(fd);  |  455 		close(fd);  | 
 455 		return NULL;  |  456 		return NULL;  | 
 456 	}  |  457 	}  | 
 457   |  458   | 
 458 	close(fd);  |  459 	close(fd);  | 
 459   |  460   | 
 460 	sprintf(broadcast, "%u.%u.%u.%u",  |  461 	sprintf(broadcast, "%u.%u.%u.%u",  | 
 461 		(unsigned int)ifr.ifr_broadaddr.sa_data[2] % 256,  |  462 		(unsigned int)ifr.ifr_broadaddr.sa_data[2] % 256,  | 
 462 		(unsigned int)ifr.ifr_broadaddr.sa_data[3] % 256,  |  463 		(unsigned int)ifr.ifr_broadaddr.sa_data[3] % 256,  | 
 463 		(unsigned int)ifr.ifr_broadaddr.sa_data[4] % 256,  |  464 		(unsigned int)ifr.ifr_broadaddr.sa_data[4] % 256,  | 
 464 		(unsigned int)ifr.ifr_broadaddr.sa_data[5] % 256);  |  465 		(unsigned int)ifr.ifr_broadaddr.sa_data[5] % 256);  | 
 465   |  466   | 
 466 	return PyString_FromString(broadcast);  |  467 	return PyString_FromString(broadcast);  | 
 467 }  |  468 }  | 
 468   |  469   | 
 469 static PyObject *get_module(PyObject *self __unused, PyObject *args)  |  470 static PyObject *get_module(PyObject *self __unused, PyObject *args)  | 
 470 { |  471 { | 
 471 	struct ethtool_cmd ecmd;  |  472 	struct ethtool_cmd ecmd;  | 
 472 	struct ifreq ifr;  |  473 	struct ifreq ifr;  | 
 473 	int fd, err;  |  474 	int fd, err;  | 
 474 	char buf[2048];  |  475 	char buf[2048];  | 
 475 	char *devname;  |  476 	const char *devname;  | 
 476   |  477   | 
 477 	if (!PyArg_ParseTuple(args, "s", &devname))    Mismatching type in call to PyArg_ParseTuple with format code "s"      argument 3 ("&devname") had type
    "char * *"
  but was expecting
    "const char * *"
  for format code "s"
    (emitted by cpychecker)   |  478 	if (!PyArg_ParseTuple(args, "s", &devname))  | 
 478 		return NULL;  |  479 		return NULL;  | 
 479   |  480   | 
 480 	/* Setup our control structures. */  |  481 	/* Setup our control structures. */  | 
 481 	memset(&ecmd, 0, sizeof(ecmd));  |  482 	memset(&ecmd, 0, sizeof(ecmd));  | 
 482 	memset(&ifr, 0, sizeof(ifr));  |  483 	memset(&ifr, 0, sizeof(ifr));  | 
 483 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  |  484 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  | 
 484 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  |  485 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  | 
 485 	ifr.ifr_data = (caddr_t) &buf;  |  486 	ifr.ifr_data = (caddr_t) &buf;  | 
 486 	ecmd.cmd = ETHTOOL_GDRVINFO;  |  487 	ecmd.cmd = ETHTOOL_GDRVINFO;  | 
 487 	memcpy(&buf, &ecmd, sizeof(ecmd));  |  488 	memcpy(&buf, &ecmd, sizeof(ecmd));  | 
 488   |  489   | 
 489 	/* Open control socket. */  |  490 	/* Open control socket. */  | 
 490 	fd = socket(AF_INET, SOCK_DGRAM, 0);  |  491 	fd = socket(AF_INET, SOCK_DGRAM, 0);  | 
 491 	if (fd < 0) { |  492 	if (fd < 0) { | 
 492 		PyErr_SetString(PyExc_OSError, strerror(errno));  |  493 		PyErr_SetString(PyExc_OSError, strerror(errno));  | 
 493 		return NULL;  |  494 		return NULL;  | 
 494 	}  |  495 	}  | 
 495   |  496   | 
 496 	/* Get current settings. */  |  497 	/* Get current settings. */  | 
 497 	err = ioctl(fd, SIOCETHTOOL, &ifr);  |  498 	err = ioctl(fd, SIOCETHTOOL, &ifr);  | 
 498   |  499   | 
 499 	if (err < 0) {  /* failed? */ |  500 	if (err < 0) {  /* failed? */ | 
 500 		int eno = errno;  |  501 		int eno = errno;  | 
 501 		FILE *file;  |  502 		FILE *file;  | 
 502 		int found = 0;  |  503 		int found = 0;  | 
 503 		char driver[100], dev[100];  |  504 		char driver[101], dev[101];  | 
 504 		close(fd);  |  505 		close(fd);  | 
 505   |  506   | 
 506 		/* Before bailing, maybe it is a PCMCIA/PC Card? */  |  507 		/* Before bailing, maybe it is a PCMCIA/PC Card? */  | 
 507 		file = fopen("/var/lib/pcmcia/stab", "r"); |  508 		file = fopen("/var/lib/pcmcia/stab", "r"); | 
 508 		if (file == NULL) { |  509 		if (file == NULL) { | 
 509 			sprintf(buf, "[Errno %d] %s", eno, strerror(eno));  |  510 			sprintf(buf, "[Errno %d] %s", eno, strerror(eno));  | 
 510 			PyErr_SetString(PyExc_IOError, buf);  |  511 			PyErr_SetString(PyExc_IOError, buf);  | 
 511 			return NULL;  |  512 			return NULL;  | 
 512 		}  |  513 		}  | 
 513   |  514   | 
 514 		while (!feof(file)) { |  515 		while (!feof(file)) { | 
 515 			if (fgets(buf, 2048, file) == NULL)  |  516 			if (fgets(buf, 2048, file) == NULL)  | 
 516 				break;  |  517 				break;  | 
 517 			buf[2047] = '\0';  |  518 			buf[2047] = '\0';  | 
 518 			if (strncmp(buf, "Socket", 6) != 0) { |  519 			if (strncmp(buf, "Socket", 6) != 0) { | 
 519 				if (sscanf(buf, "%*d\t%*s\t%100s\t%*d\t%100s\n", driver, dev) > 0) {   Width 100 given in format string (no. 1) is larger than destination buffer 'driver[100]', use %99s to prevent overflowing it.    (emitted by cppcheck)     Width 100 given in format string (no. 2) is larger than destination buffer 'dev[100]', use %99s to prevent overflowing it.    (emitted by cppcheck)   |  520 				if (sscanf(buf, "%*d\t%*s\t%100s\t%*d\t%100s\n", driver, dev) > 0) { | 
 520 					driver[99] = '\0';  |  521 					driver[99] = '\0';  | 
 521 					dev[99] = '\0';  |  522 					dev[99] = '\0';  | 
 522 					if (strcmp(devname, dev) == 0) { |  523 					if (strcmp(devname, dev) == 0) { | 
 523 						found = 1;  |  524 						found = 1;  | 
 524 						break;  |  525 						break;  | 
 525 					}  |  526 					}  | 
 526 				}  |  527 				}  | 
 527 			}  |  528 			}  | 
 528 		}  |  529 		}  | 
 529 		fclose(file);  |  530 		fclose(file);  | 
 530 		if (!found) { |  531 		if (!found) { | 
 531 			sprintf(buf, "[Errno %d] %s", eno, strerror(eno));  |  532 			sprintf(buf, "[Errno %d] %s", eno, strerror(eno));  | 
 532 			PyErr_SetString(PyExc_IOError, buf);  |  533 			PyErr_SetString(PyExc_IOError, buf);  | 
 533 			return NULL;  |  534 			return NULL;  | 
 534 		} else  |  535 		} else  | 
 535 			return PyString_FromString(driver);  |  536 			return PyString_FromString(driver);  | 
 536 	}  |  537 	}  | 
 537   |  538   | 
 538 	close(fd);  |  539 	close(fd);  | 
 539 	return PyString_FromString(((struct ethtool_drvinfo *)buf)->driver);  |  540 	return PyString_FromString(((struct ethtool_drvinfo *)buf)->driver);  | 
 540 }  |  541 }  | 
 541   |  542   | 
 542 static PyObject *get_businfo(PyObject *self __unused, PyObject *args)  |  543 static PyObject *get_businfo(PyObject *self __unused, PyObject *args)  | 
 543 { |  544 { | 
 544 	struct ethtool_cmd ecmd;  |  545 	struct ethtool_cmd ecmd;  | 
 545 	struct ifreq ifr;  |  546 	struct ifreq ifr;  | 
 546 	int fd, err;  |  547 	int fd, err;  | 
 547 	char buf[1024];  |  548 	char buf[1024];  | 
 548 	char *devname;  |  549 	const char *devname;  | 
 549   |  550   | 
 550 	if (!PyArg_ParseTuple(args, "s", &devname))    Mismatching type in call to PyArg_ParseTuple with format code "s"      argument 3 ("&devname") had type
    "char * *"
  but was expecting
    "const char * *"
  for format code "s"
    (emitted by cpychecker)   |  551 	if (!PyArg_ParseTuple(args, "s", &devname))  | 
 551 		return NULL;  |  552 		return NULL;  | 
 552   |  553   | 
 553 	/* Setup our control structures. */  |  554 	/* Setup our control structures. */  | 
 554 	memset(&ecmd, 0, sizeof(ecmd));  |  555 	memset(&ecmd, 0, sizeof(ecmd));  | 
 555 	memset(&ifr, 0, sizeof(ifr));  |  556 	memset(&ifr, 0, sizeof(ifr));  | 
 556 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  |  557 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  | 
 557 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  |  558 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  | 
 558 	ifr.ifr_data = (caddr_t) &buf;  |  559 	ifr.ifr_data = (caddr_t) &buf;  | 
 559 	ecmd.cmd = ETHTOOL_GDRVINFO;  |  560 	ecmd.cmd = ETHTOOL_GDRVINFO;  | 
 560 	memcpy(&buf, &ecmd, sizeof(ecmd));  |  561 	memcpy(&buf, &ecmd, sizeof(ecmd));  | 
 561   |  562   | 
 562 	/* Open control socket. */  |  563 	/* Open control socket. */  | 
 563 	fd = socket(AF_INET, SOCK_DGRAM, 0);  |  564 	fd = socket(AF_INET, SOCK_DGRAM, 0);  | 
 564 	if (fd < 0) { |  565 	if (fd < 0) { | 
 565 		PyErr_SetString(PyExc_OSError, strerror(errno));  |  566 		PyErr_SetString(PyExc_OSError, strerror(errno));  | 
 566 		return NULL;  |  567 		return NULL;  | 
 567 	}  |  568 	}  | 
 568   |  569   | 
 569 	/* Get current settings. */  |  570 	/* Get current settings. */  | 
 570 	err = ioctl(fd, SIOCETHTOOL, &ifr);  |  571 	err = ioctl(fd, SIOCETHTOOL, &ifr);  | 
 571   |  572   | 
 572 	if (err < 0) {  /* failed? */ |  573 	if (err < 0) {  /* failed? */ | 
 573 		int eno = errno;  |  574 		int eno = errno;  | 
 574 		close(fd);  |  575 		close(fd);  | 
 575   |  576   | 
 576 		sprintf(buf, "[Errno %d] %s", eno, strerror(eno));  |  577 		sprintf(buf, "[Errno %d] %s", eno, strerror(eno));  | 
 577 		PyErr_SetString(PyExc_IOError, buf);  |  578 		PyErr_SetString(PyExc_IOError, buf);  | 
 578 		return NULL;  |  579 		return NULL;  | 
 579 	}  |  580 	}  | 
 580   |  581   | 
 581 	close(fd);  |  582 	close(fd);  | 
 582 	return PyString_FromString(((struct ethtool_drvinfo *)buf)->bus_info);  |  583 	return PyString_FromString(((struct ethtool_drvinfo *)buf)->bus_info);  | 
 583 }  |  584 }  | 
 584   |  585   | 
 585 static int send_command(int cmd, char *devname, void *value)  |  586 static int send_command(int cmd, const char *devname, void *value)  | 
 586 { |  587 { | 
 587 	/* Setup our request structure. */  |  588 	/* Setup our request structure. */  | 
 588 	int fd, err;  |  589 	int fd, err;  | 
 589 	struct ifreq ifr;  |  590 	struct ifreq ifr;  | 
 590 	struct ethtool_value *eval = value;  |  591 	struct ethtool_value *eval = value;  | 
 591   |  592   | 
 592 	memset(&ifr, 0, sizeof(ifr));  |  593 	memset(&ifr, 0, sizeof(ifr));  | 
 593 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  |  594 	strncpy(&ifr.ifr_name[0], devname, IFNAMSIZ);  | 
 594 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  |  595 	ifr.ifr_name[IFNAMSIZ - 1] = 0;  | 
 595 	ifr.ifr_data = (caddr_t)eval;  |  596 	ifr.ifr_data = (caddr_t)eval;  | 
 596 	eval->cmd = cmd;  |  597 	eval->cmd = cmd;  | 
 597   |  598   | 
 598 	/* Open control socket. */  |  599 	/* Open control socket. */  | 
 599 	fd = socket(AF_INET, SOCK_DGRAM, 0), err;    Uninitialized variable: err    (emitted by cppcheck)   |  600 	fd = socket(AF_INET, SOCK_DGRAM, 0), err;    Uninitialized variable: err    (emitted by cppcheck)   | 
 600 	if (fd < 0) { |  601 	if (fd < 0) { | 
 601 		PyErr_SetString(PyExc_OSError, strerror(errno));  |  602 		PyErr_SetString(PyExc_OSError, strerror(errno));  | 
 602 		return -1;  |  603 		return -1;  | 
 603 	}  |  604 	}  | 
 604   |  605   | 
 605 	/* Get current settings. */  |  606 	/* Get current settings. */  | 
 606 	err = ioctl(fd, SIOCETHTOOL, &ifr);  |  607 	err = ioctl(fd, SIOCETHTOOL, &ifr);  | 
 607 	if (err < 0) { |  608 	if (err < 0) { | 
 608 		char buf[2048];  |  609 		char buf[2048];  | 
 609 		sprintf(buf, "[Errno %d] %s", errno, strerror(errno));  |  610 		sprintf(buf, "[Errno %d] %s", errno, strerror(errno));  | 
 610 		PyErr_SetString(PyExc_IOError, buf);  |  611 		PyErr_SetString(PyExc_IOError, buf);  | 
 611 	}  |  612 	}  | 
 612   |  613   | 
 613 	close(fd);  |  614 	close(fd);  | 
 614 	return err;  |  615 	return err;  | 
 615 }  |  616 }  | 
 616   |  617   | 
 617 static int get_dev_value(int cmd, PyObject *args, void *value)  |  618 static int get_dev_value(int cmd, PyObject *args, void *value)  | 
 618 { |  619 { | 
 619 	char *devname;  |  620 	const char *devname;  | 
 620 	int err = -1;  |  621 	int err = -1;  | 
 621   |  622   | 
 622 	if (PyArg_ParseTuple(args, "s", &devname))    Mismatching type in call to PyArg_ParseTuple with format code "s"      argument 3 ("&devname") had type
    "char * *"
  but was expecting
    "const char * *"
  for format code "s"
    (emitted by cpychecker)   |  623 	if (PyArg_ParseTuple(args, "s", &devname))  | 
 623 		err = send_command(cmd, devname, value);  |  624 		err = send_command(cmd, devname, value);  | 
 624   |  625   | 
 625 	return err;  |  626 	return err;  | 
 626 }  |  627 }  | 
 627   |  628   | 
 628 static int get_dev_int_value(int cmd, PyObject *args, int *value)  |  629 static int get_dev_int_value(int cmd, PyObject *args, int *value)  | 
 629 { |  630 { | 
 630 	struct ethtool_value eval;  |  631 	struct ethtool_value eval;  | 
 631 	int rc = get_dev_value(cmd, args, &eval);  |  632 	int rc = get_dev_value(cmd, args, &eval);  | 
 632   |  633   | 
 633 	if (rc == 0)  |  634 	if (rc == 0)  | 
 634 		*value = *(int *)&eval.data;  |  635 		*value = *(int *)&eval.data;  | 
 635   |  636   | 
 636 	return rc;  |  637 	return rc;  | 
 637 }  |  638 }  | 
 638   |  639   | 
 639 static int dev_set_int_value(int cmd, PyObject *args)  |  640 static int dev_set_int_value(int cmd, PyObject *args)  | 
 640 { |  641 { | 
 641 	struct ethtool_value eval;  |  642 	struct ethtool_value eval;  | 
 642 	char *devname;  |  643 	const char *devname;  | 
 643   |  644   | 
 644 	if (!PyArg_ParseTuple(args, "si", &devname, &eval.data))    Mismatching type in call to PyArg_ParseTuple with format code "si"      argument 3 ("&devname") had type
    "char * *"
  but was expecting
    "const char * *"
  for format code "s"
    (emitted by cpychecker)     Mismatching type in call to PyArg_ParseTuple with format code "si"      argument 4 ("&eval.data") had type
    "u32 *" (pointing to 32 bits)
  but was expecting
    "int *" (pointing to 32 bits)
  for format code "i"
    (emitted by cpychecker)   |  645 	if (!PyArg_ParseTuple(args, "si", &devname, &eval.data))    Mismatching type in call to PyArg_ParseTuple with format code "si"      argument 4 ("&eval.data") had type
    "u32 *" (pointing to 32 bits)
  but was expecting
    "int *" (pointing to 32 bits)
  for format code "i"
    (emitted by cpychecker)   | 
 645 		return -1;  |  646 		return -1;  | 
 646   |  647   | 
 647 	return send_command(cmd, devname, &eval);  |  648 	return send_command(cmd, devname, &eval);  | 
 648 }  |  649 }  | 
 649   |  650   | 
 650 static PyObject *get_tso(PyObject *self __unused, PyObject *args)  |  651 static PyObject *get_tso(PyObject *self __unused, PyObject *args)  | 
 651 { |  652 { | 
 652 	int value = 0;  |  653 	int value = 0;  | 
 653   |  654   | 
 654 	if (get_dev_int_value(ETHTOOL_GTSO, args, &value) < 0)  |  655 	if (get_dev_int_value(ETHTOOL_GTSO, args, &value) < 0)  | 
 655 		return NULL;  |  656 		return NULL;  | 
 656   |  657   | 
 657 	return Py_BuildValue("b", value);   Mismatching type in call to Py_BuildValue with format code "b"      argument 2 ("value.13") had type
    "int"
  but was expecting
    "char"
  for format code "b"
    (emitted by cpychecker)   |  658 	return Py_BuildValue("b", value);   Mismatching type in call to Py_BuildValue with format code "b"      argument 2 ("value.13") had type
    "int"
  but was expecting
    "char"
  for format code "b"
    (emitted by cpychecker)   | 
 658 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   |  659 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
 659   |  660   | 
 660 static PyObject *set_tso(PyObject *self __unused, PyObject *args)  |  661 static PyObject *set_tso(PyObject *self __unused, PyObject *args)  | 
 661 { |  662 { | 
 662 	if (dev_set_int_value(ETHTOOL_STSO, args) < 0)  |  663 	if (dev_set_int_value(ETHTOOL_STSO, args) < 0)  | 
 663 		return NULL;  |  664 		return NULL;  | 
 664   |  665   | 
 665 	Py_INCREF(Py_None);  |  666 	Py_INCREF(Py_None);  | 
 666 	return Py_None;  |  667 	return Py_None;  | 
 667 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   |  668 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
 668   |  669   | 
 669 static PyObject *get_ufo(PyObject *self __unused, PyObject *args)  |  670 static PyObject *get_ufo(PyObject *self __unused, PyObject *args)  | 
 670 { |  671 { | 
 671 	int value = 0;  |  672 	int value = 0;  | 
 672   |  673   | 
 673 	if (get_dev_int_value(ETHTOOL_GUFO, args, &value) < 0)  |  674 	if (get_dev_int_value(ETHTOOL_GUFO, args, &value) < 0)  | 
 674 		return NULL;  |  675 		return NULL;  | 
 675   |  676   | 
 676 	return Py_BuildValue("b", value);   Mismatching type in call to Py_BuildValue with format code "b"      argument 2 ("value.11") had type
    "int"
  but was expecting
    "char"
  for format code "b"
    (emitted by cpychecker)   |  677 	return Py_BuildValue("b", value);   Mismatching type in call to Py_BuildValue with format code "b"      argument 2 ("value.11") had type
    "int"
  but was expecting
    "char"
  for format code "b"
    (emitted by cpychecker)   | 
 677 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   |  678 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
 678   |  679   | 
 679 static PyObject *get_gso(PyObject *self __unused, PyObject *args)  |  680 static PyObject *get_gso(PyObject *self __unused, PyObject *args)  | 
 680 { |  681 { | 
 681 	int value = 0;  |  682 	int value = 0;  | 
 682   |  683   | 
 683 	if (get_dev_int_value(ETHTOOL_GGSO, args, &value) < 0)  |  684 	if (get_dev_int_value(ETHTOOL_GGSO, args, &value) < 0)  | 
 684 		return NULL;  |  685 		return NULL;  | 
 685   |  686   | 
 686 	return Py_BuildValue("b", value);   Mismatching type in call to Py_BuildValue with format code "b"      argument 2 ("value.10") had type
    "int"
  but was expecting
    "char"
  for format code "b"
    (emitted by cpychecker)   |  687 	return Py_BuildValue("b", value);   Mismatching type in call to Py_BuildValue with format code "b"      argument 2 ("value.10") had type
    "int"
  but was expecting
    "char"
  for format code "b"
    (emitted by cpychecker)   | 
 687 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   |  688 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
 688   |  689   | 
 689 static PyObject *get_sg(PyObject *self __unused, PyObject *args)  |  690 static PyObject *get_sg(PyObject *self __unused, PyObject *args)  | 
 690 { |  691 { | 
 691 	int value = 0;  |  692 	int value = 0;  | 
 692   |  693   | 
 693 	if (get_dev_int_value(ETHTOOL_GSG, args, &value) < 0)  |  694 	if (get_dev_int_value(ETHTOOL_GSG, args, &value) < 0)  | 
 694 		return NULL;  |  695 		return NULL;  | 
 695   |  696   | 
 696 	return Py_BuildValue("b", value);   Mismatching type in call to Py_BuildValue with format code "b"      argument 2 ("value.5") had type
    "int"
  but was expecting
    "char"
  for format code "b"
    (emitted by cpychecker)   |  697 	return Py_BuildValue("b", value);   Mismatching type in call to Py_BuildValue with format code "b"      argument 2 ("value.5") had type
    "int"
  but was expecting
    "char"
  for format code "b"
    (emitted by cpychecker)   | 
 697 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   |  698 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
 698   |  699   | 
 699 struct struct_desc { |  700 struct struct_desc { | 
 700 	char	       *name;  |  701 	char	       *name;  | 
 701 	unsigned short offset;  |  702 	unsigned short offset;  | 
 702 	unsigned short size;  |  703 	unsigned short size;  | 
 703 };  |  704 };  | 
 704   |  705   | 
 705 #define member_desc(type, member_name) { \ |  706 #define member_desc(type, member_name) { \ | 
 706 	.name = #member_name, \  |  707 	.name = #member_name, \  | 
 707 	.offset = offsetof(type, member_name), \  |  708 	.offset = offsetof(type, member_name), \  | 
 708 	.size = sizeof(((type *)0)->member_name), }  |  709 	.size = sizeof(((type *)0)->member_name), }  | 
 709   |  710   | 
 710 struct struct_desc ethtool_coalesce_desc[] = { |  711 struct struct_desc ethtool_coalesce_desc[] = { | 
 711 	member_desc(struct ethtool_coalesce, rx_coalesce_usecs),  |  712 	member_desc(struct ethtool_coalesce, rx_coalesce_usecs),  | 
 712 	member_desc(struct ethtool_coalesce, rx_max_coalesced_frames),  |  713 	member_desc(struct ethtool_coalesce, rx_max_coalesced_frames),  | 
 713 	member_desc(struct ethtool_coalesce, rx_coalesce_usecs_irq),  |  714 	member_desc(struct ethtool_coalesce, rx_coalesce_usecs_irq),  | 
 714 	member_desc(struct ethtool_coalesce, rx_max_coalesced_frames_irq),  |  715 	member_desc(struct ethtool_coalesce, rx_max_coalesced_frames_irq),  | 
 715 	member_desc(struct ethtool_coalesce, tx_coalesce_usecs),  |  716 	member_desc(struct ethtool_coalesce, tx_coalesce_usecs),  | 
 716 	member_desc(struct ethtool_coalesce, tx_max_coalesced_frames),  |  717 	member_desc(struct ethtool_coalesce, tx_max_coalesced_frames),  | 
 717 	member_desc(struct ethtool_coalesce, tx_coalesce_usecs_irq),  |  718 	member_desc(struct ethtool_coalesce, tx_coalesce_usecs_irq),  | 
 718 	member_desc(struct ethtool_coalesce, tx_max_coalesced_frames_irq),  |  719 	member_desc(struct ethtool_coalesce, tx_max_coalesced_frames_irq),  | 
 719 	member_desc(struct ethtool_coalesce, stats_block_coalesce_usecs),  |  720 	member_desc(struct ethtool_coalesce, stats_block_coalesce_usecs),  | 
 720 	member_desc(struct ethtool_coalesce, use_adaptive_rx_coalesce),  |  721 	member_desc(struct ethtool_coalesce, use_adaptive_rx_coalesce),  | 
 721 	member_desc(struct ethtool_coalesce, use_adaptive_tx_coalesce),  |  722 	member_desc(struct ethtool_coalesce, use_adaptive_tx_coalesce),  | 
 722 	member_desc(struct ethtool_coalesce, pkt_rate_low),  |  723 	member_desc(struct ethtool_coalesce, pkt_rate_low),  | 
 723 	member_desc(struct ethtool_coalesce, rx_coalesce_usecs_low),  |  724 	member_desc(struct ethtool_coalesce, rx_coalesce_usecs_low),  | 
 724 	member_desc(struct ethtool_coalesce, rx_max_coalesced_frames_low),  |  725 	member_desc(struct ethtool_coalesce, rx_max_coalesced_frames_low),  | 
 725 	member_desc(struct ethtool_coalesce, tx_coalesce_usecs_low),  |  726 	member_desc(struct ethtool_coalesce, tx_coalesce_usecs_low),  | 
 726 	member_desc(struct ethtool_coalesce, tx_max_coalesced_frames_low),  |  727 	member_desc(struct ethtool_coalesce, tx_max_coalesced_frames_low),  | 
 727 	member_desc(struct ethtool_coalesce, pkt_rate_high),  |  728 	member_desc(struct ethtool_coalesce, pkt_rate_high),  | 
 728 	member_desc(struct ethtool_coalesce, rx_coalesce_usecs_high),  |  729 	member_desc(struct ethtool_coalesce, rx_coalesce_usecs_high),  | 
 729 	member_desc(struct ethtool_coalesce, rx_max_coalesced_frames_high),  |  730 	member_desc(struct ethtool_coalesce, rx_max_coalesced_frames_high),  | 
 730 	member_desc(struct ethtool_coalesce, tx_coalesce_usecs_high),  |  731 	member_desc(struct ethtool_coalesce, tx_coalesce_usecs_high),  | 
 731 	member_desc(struct ethtool_coalesce, tx_max_coalesced_frames_high),  |  732 	member_desc(struct ethtool_coalesce, tx_max_coalesced_frames_high),  | 
 732 	member_desc(struct ethtool_coalesce, rate_sample_interval),  |  733 	member_desc(struct ethtool_coalesce, rate_sample_interval),  | 
 733 };  |  734 };  | 
 734   |  735   | 
 735 static PyObject *__struct_desc_create_dict(struct struct_desc *table,  |  736 static PyObject *__struct_desc_create_dict(struct struct_desc *table,  | 
 736 					   int nr_entries, void *values)  |  737 					   int nr_entries, void *values)  | 
 737 { |  738 { | 
 738 	int i;  |  739 	int i;  | 
 739 	PyObject *dict = PyDict_New();  |  740 	PyObject *dict = PyDict_New();  | 
 740   |  741   | 
 741 	if (dict == NULL)  |  742 	if (dict == NULL)  | 
 742 		goto out;  |  743 		goto out;  | 
 743   |  744   | 
 744 	for (i = 0; i < nr_entries; ++i) { |  745 	for (i = 0; i < nr_entries; ++i) { | 
 745 		struct struct_desc *d = &table[i];  |  746 		struct struct_desc *d = &table[i];  | 
 746 		PyObject *objval = NULL;  |  747 		PyObject *objval = NULL;  | 
 747 		void *val = values + d->offset;  |  748 		void *val = values + d->offset;  | 
 748   |  749   | 
 749 		switch (d->size) { |  750 		switch (d->size) { | 
 750 		case sizeof(uint32_t):  |  751 		case sizeof(uint32_t):  | 
 751 			objval = PyInt_FromLong(*(uint32_t *)val);  |  752 			objval = PyInt_FromLong(*(uint32_t *)val);  | 
 752 			break;  |  753 			break;  | 
 753 		}  |  754 		}  | 
 754   |  755   | 
 755 		if (objval == NULL)  |  756 		if (objval == NULL)  | 
 756 			goto free_dict;  |  757 			goto free_dict;  | 
 757   |  758   | 
 758 		if (PyDict_SetItemString(dict, d->name, objval) != 0) { |  759 		if (PyDict_SetItemString(dict, d->name, objval) != 0) { | 
 759 			Py_DECREF(objval);  |  760 			Py_DECREF(objval);  | 
 760 			goto free_dict;  |  761 			goto free_dict;  | 
 761 		}  |  762 		}  | 
 762 			  |  763 			  | 
 763 		Py_DECREF(objval);  |  764 		Py_DECREF(objval);  | 
 764 	}  |  765 	}  | 
 765 out:  |  766 out:  | 
 766 	return dict;  |  767 	return dict;  | 
 767 free_dict:  |  768 free_dict:  | 
 768 	goto out;  |  769 	goto out;  | 
 769 	dict = NULL;  |  770 	dict = NULL;  | 
 770 }  |  771 }  | 
 771   |  772   | 
 772 #define struct_desc_create_dict(table, values) \  |  773 #define struct_desc_create_dict(table, values) \  | 
 773 	__struct_desc_create_dict(table, ARRAY_SIZE(table), values)  |  774 	__struct_desc_create_dict(table, ARRAY_SIZE(table), values)  | 
 774   |  775   | 
 775 static int __struct_desc_from_dict(struct struct_desc *table,  |  776 static int __struct_desc_from_dict(struct struct_desc *table,  | 
 776 				   int nr_entries, void *to, PyObject *dict)  |  777 				   int nr_entries, void *to, PyObject *dict)  | 
 777 { |  778 { | 
 778 	char buf[2048];  |  779 	char buf[2048];  | 
 779 	int i;  |  780 	int i;  | 
 780   |  781   | 
 781 	for (i = 0; i < nr_entries; ++i) { |  782 	for (i = 0; i < nr_entries; ++i) { | 
 782 		struct struct_desc *d = &table[i];  |  783 		struct struct_desc *d = &table[i];  | 
 783 		void *val = to + d->offset;  |  784 		void *val = to + d->offset;  | 
 784 		PyObject *obj;  |  785 		PyObject *obj;  | 
 785   |  786   | 
 786 		switch (d->size) { |  787 		switch (d->size) { | 
 787 		case sizeof(uint32_t):  |  788 		case sizeof(uint32_t):  | 
 788 			obj = PyDict_GetItemString(dict, d->name);  |  789 			obj = PyDict_GetItemString(dict, d->name);  | 
 789 			if (obj == NULL) { |  790 			if (obj == NULL) { | 
 790 				snprintf(buf, sizeof(buf),  |  791 				snprintf(buf, sizeof(buf),  | 
 791 					"Missing dict entry for field %s",  |  792 					"Missing dict entry for field %s",  | 
 792 					d->name);  |  793 					d->name);  | 
 793 				PyErr_SetString(PyExc_IOError, buf);  |  794 				PyErr_SetString(PyExc_IOError, buf);  | 
 794 				return -1;  |  795 				return -1;  | 
 795 			}  |  796 			}  | 
 796 			*(uint32_t *)val = PyInt_AsLong(obj);  |  797 			*(uint32_t *)val = PyInt_AsLong(obj);  | 
 797 			break;  |  798 			break;  | 
 798 		default:  |  799 		default:  | 
 799 			snprintf(buf, sizeof(buf),  |  800 			snprintf(buf, sizeof(buf),  | 
 800 				 "Invalid type size %d for field %s",  |  801 				 "Invalid type size %d for field %s",  | 
 801 				 d->size, d->name);  |  802 				 d->size, d->name);  | 
 802 			PyErr_SetString(PyExc_IOError, buf);  |  803 			PyErr_SetString(PyExc_IOError, buf);  | 
 803 			return -1;  |  804 			return -1;  | 
 804 		}  |  805 		}  | 
 805 	}  |  806 	}  | 
 806   |  807   | 
 807 	return 0;  |  808 	return 0;  | 
 808 }  |  809 }  | 
 809   |  810   | 
 810 #define struct_desc_from_dict(table, to, dict) \  |  811 #define struct_desc_from_dict(table, to, dict) \  | 
 811 	__struct_desc_from_dict(table, ARRAY_SIZE(table), to, dict)  |  812 	__struct_desc_from_dict(table, ARRAY_SIZE(table), to, dict)  | 
 812   |  813   | 
 813 static PyObject *get_coalesce(PyObject *self __unused, PyObject *args)  |  814 static PyObject *get_coalesce(PyObject *self __unused, PyObject *args)  | 
 814 { |  815 { | 
 815 	struct ethtool_coalesce coal;  |  816 	struct ethtool_coalesce coal;  | 
 816   |  817   | 
 817 	if (get_dev_value(ETHTOOL_GCOALESCE, args, &coal) < 0)  |  818 	if (get_dev_value(ETHTOOL_GCOALESCE, args, &coal) < 0)  | 
 818 		return NULL;  |  819 		return NULL;  | 
 819   |  820   | 
 820 	return struct_desc_create_dict(ethtool_coalesce_desc, &coal);  |  821 	return struct_desc_create_dict(ethtool_coalesce_desc, &coal);  | 
 821 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   |  822 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
 822   |  823   | 
 823 static PyObject *set_coalesce(PyObject *self __unused, PyObject *args)  |  824 static PyObject *set_coalesce(PyObject *self __unused, PyObject *args)  | 
 824 { |  825 { | 
 825 	struct ethtool_coalesce coal;  |  826 	struct ethtool_coalesce coal;  | 
 826 	char *devname;  |  827 	const char *devname;  | 
 827 	PyObject *dict;  |  828 	PyObject *dict;  | 
 828   |  829   | 
 829 	if (!PyArg_ParseTuple(args, "sO", &devname, &dict))    Mismatching type in call to PyArg_ParseTuple with format code "sO"      argument 3 ("&devname") had type
    "char * *"
  but was expecting
    "const char * *"
  for format code "s"
    (emitted by cpychecker)   |  830 	if (!PyArg_ParseTuple(args, "sO", &devname, &dict))  | 
 830 		return NULL;  |  831 		return NULL;  | 
 831   |  832   | 
 832 	if (struct_desc_from_dict(ethtool_coalesce_desc, &coal, dict) != 0)  |  833 	if (struct_desc_from_dict(ethtool_coalesce_desc, &coal, dict) != 0)  | 
 833 		return NULL;  |  834 		return NULL;  | 
 834   |  835   | 
 835 	if (send_command(ETHTOOL_SCOALESCE, devname, &coal))  |  836 	if (send_command(ETHTOOL_SCOALESCE, devname, &coal))  | 
 836 		return NULL;  |  837 		return NULL;  | 
 837   |  838   | 
 838 	Py_INCREF(Py_None);  |  839 	Py_INCREF(Py_None);  | 
 839 	return Py_None;  |  840 	return Py_None;  | 
 840 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   |  841 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
 841   |  842   | 
 842 struct struct_desc ethtool_ringparam_desc[] = { |  843 struct struct_desc ethtool_ringparam_desc[] = { | 
 843 	member_desc(struct ethtool_ringparam, rx_max_pending),  |  844 	member_desc(struct ethtool_ringparam, rx_max_pending),  | 
 844 	member_desc(struct ethtool_ringparam, rx_mini_max_pending),  |  845 	member_desc(struct ethtool_ringparam, rx_mini_max_pending),  | 
 845 	member_desc(struct ethtool_ringparam, rx_jumbo_max_pending),  |  846 	member_desc(struct ethtool_ringparam, rx_jumbo_max_pending),  | 
 846 	member_desc(struct ethtool_ringparam, tx_max_pending),  |  847 	member_desc(struct ethtool_ringparam, tx_max_pending),  | 
 847 	member_desc(struct ethtool_ringparam, rx_pending),  |  848 	member_desc(struct ethtool_ringparam, rx_pending),  | 
 848 	member_desc(struct ethtool_ringparam, rx_mini_pending),  |  849 	member_desc(struct ethtool_ringparam, rx_mini_pending),  | 
 849 	member_desc(struct ethtool_ringparam, rx_jumbo_pending),  |  850 	member_desc(struct ethtool_ringparam, rx_jumbo_pending),  | 
 850 	member_desc(struct ethtool_ringparam, tx_pending),  |  851 	member_desc(struct ethtool_ringparam, tx_pending),  | 
 851 };  |  852 };  | 
 852   |  853   | 
 853 static PyObject *get_ringparam(PyObject *self __unused, PyObject *args)  |  854 static PyObject *get_ringparam(PyObject *self __unused, PyObject *args)  | 
 854 { |  855 { | 
 855 	struct ethtool_ringparam ring;  |  856 	struct ethtool_ringparam ring;  | 
 856   |  857   | 
 857 	if (get_dev_value(ETHTOOL_GRINGPARAM, args, &ring) < 0)  |  858 	if (get_dev_value(ETHTOOL_GRINGPARAM, args, &ring) < 0)  | 
 858 		return NULL;  |  859 		return NULL;  | 
 859   |  860   | 
 860 	return struct_desc_create_dict(ethtool_ringparam_desc, &ring);  |  861 	return struct_desc_create_dict(ethtool_ringparam_desc, &ring);  | 
 861 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   |  862 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
 862   |  863   | 
 863 static PyObject *set_ringparam(PyObject *self __unused, PyObject *args)  |  864 static PyObject *set_ringparam(PyObject *self __unused, PyObject *args)  | 
 864 { |  865 { | 
 865 	struct ethtool_ringparam ring;  |  866 	struct ethtool_ringparam ring;  | 
 866 	char *devname;  |  867 	const char *devname;  | 
 867 	PyObject *dict;  |  868 	PyObject *dict;  | 
 868   |  869   | 
 869 	if (!PyArg_ParseTuple(args, "sO", &devname, &dict))    Mismatching type in call to PyArg_ParseTuple with format code "sO"      argument 3 ("&devname") had type
    "char * *"
  but was expecting
    "const char * *"
  for format code "s"
    (emitted by cpychecker)   |  870 	if (!PyArg_ParseTuple(args, "sO", &devname, &dict))  | 
 870 		return NULL;  |  871 		return NULL;  | 
 871   |  872   | 
 872 	if (struct_desc_from_dict(ethtool_ringparam_desc, &ring, dict) != 0)  |  873 	if (struct_desc_from_dict(ethtool_ringparam_desc, &ring, dict) != 0)  | 
 873 		return NULL;  |  874 		return NULL;  | 
 874   |  875   | 
 875 	if (send_command(ETHTOOL_SRINGPARAM, devname, &ring))  |  876 	if (send_command(ETHTOOL_SRINGPARAM, devname, &ring))  | 
 876 		return NULL;  |  877 		return NULL;  | 
 877   |  878   | 
 878 	Py_INCREF(Py_None);  |  879 	Py_INCREF(Py_None);  | 
 879 	return Py_None;  |  880 	return Py_None;  | 
 880 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   |  881 }    returning (PyObject*)NULL without setting an exception    (emitted by cpychecker) TODO: a detailed trace is available in the data model (not yet rendered in this report)   | 
 881   |  882   | 
 882 static struct PyMethodDef PyEthModuleMethods[] = { |  883 static struct PyMethodDef PyEthModuleMethods[] = { | 
 883 	{ |  884 	{ | 
 884 		.ml_name = "get_module",  |  885 		.ml_name = "get_module",  | 
 885 		.ml_meth = (PyCFunction)get_module,  |  886 		.ml_meth = (PyCFunction)get_module,  | 
 886 		.ml_flags = METH_VARARGS,  |  887 		.ml_flags = METH_VARARGS,  | 
 887 	},  |  888 	},  | 
 888 	{ |  889 	{ | 
 889 		.ml_name = "get_businfo",  |  890 		.ml_name = "get_businfo",  | 
 890 		.ml_meth = (PyCFunction)get_businfo,  |  891 		.ml_meth = (PyCFunction)get_businfo,  | 
 891 		.ml_flags = METH_VARARGS,  |  892 		.ml_flags = METH_VARARGS,  | 
 892 	},  |  893 	},  | 
 893 	{ |  894 	{ | 
 894 		.ml_name = "get_hwaddr",  |  895 		.ml_name = "get_hwaddr",  | 
 895 		.ml_meth = (PyCFunction)get_hwaddress,  |  896 		.ml_meth = (PyCFunction)get_hwaddress,  | 
 896 		.ml_flags = METH_VARARGS,  |  897 		.ml_flags = METH_VARARGS,  | 
 897 	},  |  898 	},  | 
 898 	{ |  899 	{ | 
 899 		.ml_name = "get_ipaddr",  |  900 		.ml_name = "get_ipaddr",  | 
 900 		.ml_meth = (PyCFunction)get_ipaddress,  |  901 		.ml_meth = (PyCFunction)get_ipaddress,  | 
 901 		.ml_flags = METH_VARARGS,  |  902 		.ml_flags = METH_VARARGS,  | 
 902 	},  |  903 	},  | 
 903 	{ |  904 	{ | 
 904 		.ml_name = "get_interfaces_info",  |  905 		.ml_name = "get_interfaces_info",  | 
 905 		.ml_meth = (PyCFunction)get_interfaces_info,  |  906 		.ml_meth = (PyCFunction)get_interfaces_info,  | 
 906 		.ml_flags = METH_VARARGS,  |  907 		.ml_flags = METH_VARARGS,  | 
 907 		.ml_doc = "Accepts a string, list or tupples of interface names. "  |  908 		.ml_doc = "Accepts a string, list or tupples of interface names. "  | 
 908 		"Returns a list of ethtool.etherinfo objets with device information."  |  909 		"Returns a list of ethtool.etherinfo objets with device information."  | 
 909 	},  |  910 	},  | 
 910 	{ |  911 	{ | 
 911 		.ml_name = "get_netmask",  |  912 		.ml_name = "get_netmask",  | 
 912 		.ml_meth = (PyCFunction)get_netmask,  |  913 		.ml_meth = (PyCFunction)get_netmask,  | 
 913 		.ml_flags = METH_VARARGS,  |  914 		.ml_flags = METH_VARARGS,  | 
 914 	},  |  915 	},  | 
 915 	{ |  916 	{ | 
 916 		.ml_name = "get_broadcast",  |  917 		.ml_name = "get_broadcast",  | 
 917 		.ml_meth = (PyCFunction)get_broadcast,  |  918 		.ml_meth = (PyCFunction)get_broadcast,  | 
 918 		.ml_flags = METH_VARARGS,  |  919 		.ml_flags = METH_VARARGS,  | 
 919 	},  |  920 	},  | 
 920 	{ |  921 	{ | 
 921 		.ml_name = "get_coalesce",  |  922 		.ml_name = "get_coalesce",  | 
 922 		.ml_meth = (PyCFunction)get_coalesce,  |  923 		.ml_meth = (PyCFunction)get_coalesce,  | 
 923 		.ml_flags = METH_VARARGS,  |  924 		.ml_flags = METH_VARARGS,  | 
 924 	},  |  925 	},  | 
 925 	{ |  926 	{ | 
 926 		.ml_name = "set_coalesce",  |  927 		.ml_name = "set_coalesce",  | 
 927 		.ml_meth = (PyCFunction)set_coalesce,  |  928 		.ml_meth = (PyCFunction)set_coalesce,  | 
 928 		.ml_flags = METH_VARARGS,  |  929 		.ml_flags = METH_VARARGS,  | 
 929 	},  |  930 	},  | 
 930 	{ |  931 	{ | 
 931 		.ml_name = "get_devices",  |  932 		.ml_name = "get_devices",  | 
 932 		.ml_meth = (PyCFunction)get_devices,  |  933 		.ml_meth = (PyCFunction)get_devices,  | 
 933 		.ml_flags = METH_VARARGS,  |  934 		.ml_flags = METH_VARARGS,  | 
 934 	},  |  935 	},  | 
 935 	{ |  936 	{ | 
 936 		.ml_name = "get_active_devices",  |  937 		.ml_name = "get_active_devices",  | 
 937 		.ml_meth = (PyCFunction)get_active_devices,  |  938 		.ml_meth = (PyCFunction)get_active_devices,  | 
 938 		.ml_flags = METH_VARARGS,  |  939 		.ml_flags = METH_VARARGS,  | 
 939 	},  |  940 	},  | 
 940 	{ |  941 	{ | 
 941 		.ml_name = "get_ringparam",  |  942 		.ml_name = "get_ringparam",  | 
 942 		.ml_meth = (PyCFunction)get_ringparam,  |  943 		.ml_meth = (PyCFunction)get_ringparam,  | 
 943 		.ml_flags = METH_VARARGS,  |  944 		.ml_flags = METH_VARARGS,  | 
 944 	},  |  945 	},  | 
 945 	{ |  946 	{ | 
 946 		.ml_name = "set_ringparam",  |  947 		.ml_name = "set_ringparam",  | 
 947 		.ml_meth = (PyCFunction)set_ringparam,  |  948 		.ml_meth = (PyCFunction)set_ringparam,  | 
 948 		.ml_flags = METH_VARARGS,  |  949 		.ml_flags = METH_VARARGS,  | 
 949 	},  |  950 	},  | 
 950 	{ |  951 	{ | 
 951 		.ml_name = "get_tso",  |  952 		.ml_name = "get_tso",  | 
 952 		.ml_meth = (PyCFunction)get_tso,  |  953 		.ml_meth = (PyCFunction)get_tso,  | 
 953 		.ml_flags = METH_VARARGS,  |  954 		.ml_flags = METH_VARARGS,  | 
 954 	},  |  955 	},  | 
 955 	{ |  956 	{ | 
 956 		.ml_name = "set_tso",  |  957 		.ml_name = "set_tso",  | 
 957 		.ml_meth = (PyCFunction)set_tso,  |  958 		.ml_meth = (PyCFunction)set_tso,  | 
 958 		.ml_flags = METH_VARARGS,  |  959 		.ml_flags = METH_VARARGS,  | 
 959 	},  |  960 	},  | 
 960 	{ |  961 	{ | 
 961 		.ml_name = "get_ufo",  |  962 		.ml_name = "get_ufo",  | 
 962 		.ml_meth = (PyCFunction)get_ufo,  |  963 		.ml_meth = (PyCFunction)get_ufo,  | 
 963 		.ml_flags = METH_VARARGS,  |  964 		.ml_flags = METH_VARARGS,  | 
 964 	},  |  965 	},  | 
 965 	{ |  966 	{ | 
 966 		.ml_name = "get_gso",  |  967 		.ml_name = "get_gso",  | 
 967 		.ml_meth = (PyCFunction)get_gso,  |  968 		.ml_meth = (PyCFunction)get_gso,  | 
 968 		.ml_flags = METH_VARARGS,  |  969 		.ml_flags = METH_VARARGS,  | 
 969 	},  |  970 	},  | 
 970 	{ |  971 	{ | 
 971 		.ml_name = "get_sg",  |  972 		.ml_name = "get_sg",  | 
 972 		.ml_meth = (PyCFunction)get_sg,  |  973 		.ml_meth = (PyCFunction)get_sg,  | 
 973 		.ml_flags = METH_VARARGS,  |  974 		.ml_flags = METH_VARARGS,  | 
 974 	},  |  975 	},  | 
 975 	{ |  976 	{ | 
 976 		.ml_name = "get_flags",  |  977 		.ml_name = "get_flags",  | 
 977 		.ml_meth = (PyCFunction)get_flags,  |  978 		.ml_meth = (PyCFunction)get_flags,  | 
 978 		.ml_flags = METH_VARARGS,  |  979 		.ml_flags = METH_VARARGS,  | 
 979 	},  |  980 	},  | 
 980 	{	.ml_name = NULL, }, |  981 	{	.ml_name = NULL, }, | 
 981 };  |  982 };  | 
 982   |  983   | 
 983   |  984   | 
 984 PyMODINIT_FUNC initethtool(void)  |  985 PyMODINIT_FUNC initethtool(void)  | 
 985 { |  986 { | 
 986 	PyObject *m;  |  987 	PyObject *m;  | 
 987 	m = Py_InitModule3("ethtool", PyEthModuleMethods, "Python ethtool module"); |  988 	m = Py_InitModule3("ethtool", PyEthModuleMethods, "Python ethtool module"); | 
 988   |  989   | 
 989 	// Prepare the ethtool.etherinfo class  |  990 	// Prepare the ethtool.etherinfo class  | 
 990 	if (PyType_Ready(ðtool_etherinfoType) < 0)  |  991 	if (PyType_Ready(ðtool_etherinfoType) < 0)  | 
 991 		return;  |  992 		return;  | 
 992 	Py_INCREF(ðtool_etherinfoType);  |  993 	Py_INCREF(ðtool_etherinfoType);  | 
 993 	PyModule_AddObject(m, "etherinfo", (PyObject *)ðtool_etherinfoType);  |  994 	PyModule_AddObject(m, "etherinfo", (PyObject *)ðtool_etherinfoType);  | 
 994   |  995   | 
 995 	// Prepare the ethtool.etherinfo_ipv6addr class  |  996 	// Prepare the ethtool.etherinfo_ipv6addr class  | 
 996 	if (PyType_Ready(ðtool_etherinfoIPv6Type) < 0)  |  997 	if (PyType_Ready(ðtool_etherinfoIPv6Type) < 0)  | 
 997 		return;  |  998 		return;  | 
 998 	Py_INCREF(ðtool_etherinfoIPv6Type);  |  999 	Py_INCREF(ðtool_etherinfoIPv6Type);  | 
 999 	PyModule_AddObject(m, "etherinfo_ipv6addr", (PyObject *)ðtool_etherinfoIPv6Type);  | 1000 	PyModule_AddObject(m, "etherinfo_ipv6addr", (PyObject *)ðtool_etherinfoIPv6Type);  | 
 | 1001   | 
 | 1002 	if (PyType_Ready(ðtool_netlink_ipv4_address_Type))  | 
 | 1003 		return;  | 
1000   | 1004   | 
1001 	// Setup constants  | 1005 	// Setup constants  | 
1002 	PyModule_AddIntConstant(m, "IFF_UP", IFF_UP);			/* Interface is up. */  | 1006 	PyModule_AddIntConstant(m, "IFF_UP", IFF_UP);			/* Interface is up. */  | 
1003 	PyModule_AddIntConstant(m, "IFF_BROADCAST", IFF_BROADCAST);	/* Broadcast address valid. */  | 1007 	PyModule_AddIntConstant(m, "IFF_BROADCAST", IFF_BROADCAST);	/* Broadcast address valid. */  | 
1004 	PyModule_AddIntConstant(m, "IFF_DEBUG", IFF_DEBUG);		/* Turn on debugging. */  | 1008 	PyModule_AddIntConstant(m, "IFF_DEBUG", IFF_DEBUG);		/* Turn on debugging. */  | 
1005 	PyModule_AddIntConstant(m, "IFF_LOOPBACK", IFF_LOOPBACK);	/* Is a loopback net */  | 1009 	PyModule_AddIntConstant(m, "IFF_LOOPBACK", IFF_LOOPBACK);	/* Is a loopback net */  | 
1006 	PyModule_AddIntConstant(m, "IFF_POINTOPOINT", IFF_POINTOPOINT); /* Is a point-to-point link */  | 1010 	PyModule_AddIntConstant(m, "IFF_POINTOPOINT", IFF_POINTOPOINT); /* Is a point-to-point link */  | 
1007 	PyModule_AddIntConstant(m, "IFF_NOTRAILERS", IFF_NOTRAILERS);	/* Avoid use of trailers */  | 1011 	PyModule_AddIntConstant(m, "IFF_NOTRAILERS", IFF_NOTRAILERS);	/* Avoid use of trailers */  | 
1008 	PyModule_AddIntConstant(m, "IFF_RUNNING", IFF_RUNNING);		/* Resources allocated */  | 1012 	PyModule_AddIntConstant(m, "IFF_RUNNING", IFF_RUNNING);		/* Resources allocated */  | 
1009 	PyModule_AddIntConstant(m, "IFF_NOARP", IFF_NOARP);		/* No address resolution protocol. */  | 1013 	PyModule_AddIntConstant(m, "IFF_NOARP", IFF_NOARP);		/* No address resolution protocol. */  | 
1010 	PyModule_AddIntConstant(m, "IFF_PROMISC", IFF_PROMISC);		/* Receive all packets. */  | 1014 	PyModule_AddIntConstant(m, "IFF_PROMISC", IFF_PROMISC);		/* Receive all packets. */  | 
1011 	PyModule_AddIntConstant(m, "IFF_ALLMULTI", IFF_ALLMULTI);	/* Receive all multicast packets. */  | 1015 	PyModule_AddIntConstant(m, "IFF_ALLMULTI", IFF_ALLMULTI);	/* Receive all multicast packets. */  | 
1012 	PyModule_AddIntConstant(m, "IFF_MASTER", IFF_MASTER);		/* Master of a load balancer. */  | 1016 	PyModule_AddIntConstant(m, "IFF_MASTER", IFF_MASTER);		/* Master of a load balancer. */  | 
1013 	PyModule_AddIntConstant(m, "IFF_SLAVE", IFF_SLAVE);		/* Slave of a load balancer. */  | 1017 	PyModule_AddIntConstant(m, "IFF_SLAVE", IFF_SLAVE);		/* Slave of a load balancer. */  | 
1014 	PyModule_AddIntConstant(m, "IFF_MULTICAST", IFF_MULTICAST);	/* Supports multicast. */  | 1018 	PyModule_AddIntConstant(m, "IFF_MULTICAST", IFF_MULTICAST);	/* Supports multicast. */  | 
1015 	PyModule_AddIntConstant(m, "IFF_PORTSEL", IFF_PORTSEL);		/* Can set media type. */  | 1019 	PyModule_AddIntConstant(m, "IFF_PORTSEL", IFF_PORTSEL);		/* Can set media type. */  | 
1016 	PyModule_AddIntConstant(m, "IFF_AUTOMEDIA", IFF_AUTOMEDIA);	/* Auto media select active. */  | 1020 	PyModule_AddIntConstant(m, "IFF_AUTOMEDIA", IFF_AUTOMEDIA);	/* Auto media select active. */  | 
1017 	PyModule_AddIntConstant(m, "IFF_DYNAMIC", IFF_DYNAMIC);		/* Dialup device with changing addresses.  */  | 1021 	PyModule_AddIntConstant(m, "IFF_DYNAMIC", IFF_DYNAMIC);		/* Dialup device with changing addresses.  */  | 
1018 	PyModule_AddIntConstant(m, "AF_INET", AF_INET);                 /* IPv4 interface */  | 1022 	PyModule_AddIntConstant(m, "AF_INET", AF_INET);                 /* IPv4 interface */  | 
1019 	PyModule_AddIntConstant(m, "AF_INET6", AF_INET6);               /* IPv6 interface */  | 1023 	PyModule_AddIntConstant(m, "AF_INET6", AF_INET6);               /* IPv6 interface */  | 
1020 	PyModule_AddStringConstant(m, "version", "python-ethtool v" VERSION);  | 1024 	PyModule_AddStringConstant(m, "version", "python-ethtool v" VERSION);  | 
1021 }  | 1025 }  | 
  | 
  |