ctdb-vacuum: update comment for ctdb_process_delete_queue
[Samba.git] / ctdb / common / system_aix.c
blob41f61aecb5d995b42b6c33391ea3682c77fe8ac4
1 /*
2 ctdb system specific code to manage raw sockets on aix
4 Copyright (C) Ronnie Sahlberg 2007
5 Copyright (C) Andrew Tridgell 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "system/network.h"
24 #include "system/filesys.h"
25 #include "system/wait.h"
26 #include "../include/ctdb_private.h"
27 #include <netinet/if_ether.h>
28 #include <netinet/ip6.h>
29 #include <net/if_arp.h>
30 #include <sys/ndd_var.h>
31 #include <sys/kinfo.h>
32 #include <pcap.h>
36 #if 0
37 This function is no longer used and its code should be moved into
38 send tcp packet after that function has been enhanced to do ipv6 as well.
40 /* This function is used to open a raw socket to send tickles from
42 int ctdb_sys_open_sending_socket(void)
44 int s, ret;
45 uint32_t one = 1;
47 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
48 if (s == -1) {
49 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
50 strerror(errno)));
51 return -1;
54 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
55 if (ret != 0) {
56 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
57 strerror(errno)));
58 close(s);
59 return -1;
62 set_nonblocking(s);
63 set_close_on_exec(s);
65 return s;
67 #endif
70 simple TCP checksum - assumes data is multiple of 2 bytes long
72 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
74 uint32_t sum = uint16_checksum(data, n);
75 uint16_t sum2;
77 sum += uint16_checksum((uint16_t *)&ip->ip_src, sizeof(ip->ip_src));
78 sum += uint16_checksum((uint16_t *)&ip->ip_dst, sizeof(ip->ip_dst));
79 sum += ip->ip_p + n;
80 sum = (sum & 0xFFFF) + (sum >> 16);
81 sum = (sum & 0xFFFF) + (sum >> 16);
82 sum2 = htons(sum);
83 sum2 = ~sum2;
84 if (sum2 == 0) {
85 return 0xFFFF;
87 return sum2;
91 Send tcp segment from the specified IP/port to the specified
92 destination IP/port.
94 This is used to trigger the receiving host into sending its own ACK,
95 which should trigger early detection of TCP reset by the client
96 after IP takeover
98 This can also be used to send RST segments (if rst is true) and also
99 if correct seq and ack numbers are provided.
101 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
102 const ctdb_sock_addr *src,
103 uint32_t seq, uint32_t ack, int rst)
105 int s;
106 int ret;
107 uint32_t one = 1;
108 ctdb_sock_addr *tmpdest;
110 struct {
111 struct ip ip;
112 struct tcphdr tcp;
113 } ip4pkt;
116 /* for now, we only handle AF_INET addresses */
117 if (src->ip.sin_family != AF_INET || dest->ip.sin_family != AF_INET) {
118 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address\n"));
119 return -1;
124 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
125 if (s == -1) {
126 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
127 strerror(errno)));
128 return -1;
131 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
132 if (ret != 0) {
133 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
134 strerror(errno)));
135 close(s);
136 return -1;
139 set_nonblocking(s);
140 set_close_on_exec(s);
142 memset(&ip4pkt, 0, sizeof(ip4pkt));
143 ip4pkt.ip.ip_v = 4;
144 ip4pkt.ip.ip_hl = sizeof(ip4pkt.ip)/4;
145 ip4pkt.ip.ip_len = htons(sizeof(ip4pkt));
146 ip4pkt.ip.ip_ttl = 255;
147 ip4pkt.ip.ip_p = IPPROTO_TCP;
148 ip4pkt.ip.ip_src.s_addr = src->ip.sin_addr.s_addr;
149 ip4pkt.ip.ip_dst.s_addr = dest->ip.sin_addr.s_addr;
150 ip4pkt.ip.ip_sum = 0;
152 ip4pkt.tcp.th_sport = src->ip.sin_port;
153 ip4pkt.tcp.th_dport = dest->ip.sin_port;
154 ip4pkt.tcp.th_seq = seq;
155 ip4pkt.tcp.th_ack = ack;
156 ip4pkt.tcp.th_flags = TH_ACK;
157 if (rst) {
158 ip4pkt.tcp.th_flags = TH_RST;
160 ip4pkt.tcp.th_off = sizeof(ip4pkt.tcp)/4;
161 ip4pkt.tcp.th_win = htons(1234);
162 ip4pkt.tcp.th_sum = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
164 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0, (struct sockaddr *)dest, sizeof(*dest));
165 if (ret != sizeof(ip4pkt)) {
166 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
167 return -1;
170 return 0;
173 /* This function is used to open a raw socket to capture from
175 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
177 pcap_t *pt;
179 pt=pcap_open_live(iface, 100, 0, 0, NULL);
180 if (pt == NULL) {
181 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
182 return -1;
184 *((pcap_t **)private_data) = pt;
186 return pcap_fileno(pt);
190 /* This function is used to close the capture socket
192 int ctdb_sys_close_capture_socket(void *private_data)
194 pcap_t *pt = (pcap_t *)private_data;
195 pcap_close(pt);
196 return 0;
202 send gratuitous arp reply after we have taken over an ip address
204 saddr is the address we are trying to claim
205 iface is the interface name we will be using to claim the address
207 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
209 /* FIXME AIX: We dont do gratuitous arp yet */
210 return -1;
216 get ethernet MAC address on AIX
218 static int aix_get_mac_addr(const char *device_name, uint8_t mac[6])
220 size_t ksize;
221 struct kinfo_ndd *ndd;
222 int count, i;
224 ksize = getkerninfo(KINFO_NDD, 0, 0, 0);
225 if (ksize == 0) {
226 errno = ENOSYS;
227 return -1;
230 ndd = (struct kinfo_ndd *)malloc(ksize);
231 if (ndd == NULL) {
232 errno = ENOMEM;
233 return -1;
236 if (getkerninfo(KINFO_NDD, ndd, &ksize, 0) == -1) {
237 errno = ENOSYS;
238 return -1;
241 count= ksize/sizeof(struct kinfo_ndd);
242 for (i=0;i<count;i++) {
243 if ( (ndd[i].ndd_type != NDD_ETHER)
244 && (ndd[i].ndd_type != NDD_ISO88023) ) {
245 continue;
247 if (ndd[i].ndd_addrlen != 6) {
248 continue;
250 if (!(ndd[i].ndd_flags&NDD_UP)) {
251 continue;
253 if ( strcmp(device_name, ndd[i].ndd_name)
254 && strcmp(device_name, ndd[i].ndd_alias) ) {
255 continue;
257 memcpy(mac, ndd[i].ndd_addr, 6);
258 free(ndd);
259 return 0;
261 free(ndd);
262 errno = ENOENT;
263 return -1;
266 int ctdb_sys_read_tcp_packet(int s, void *private_data,
267 ctdb_sock_addr *src, ctdb_sock_addr *dst,
268 uint32_t *ack_seq, uint32_t *seq)
270 int ret;
271 struct ether_header *eth;
272 struct ip *ip;
273 struct ip6_hdr *ip6;
274 struct tcphdr *tcp;
275 struct ctdb_killtcp_connection *conn;
276 struct pcap_pkthdr pkthdr;
277 const u_char *buffer;
278 pcap_t *pt = (pcap_t *)private_data;
280 buffer=pcap_next(pt, &pkthdr);
281 if (buffer==NULL) {
282 return -1;
285 /* Ethernet */
286 eth = (struct ether_header *)buffer;
288 /* we want either IPv4 or IPv6 */
289 if (eth->ether_type == htons(ETHERTYPE_IP)) {
290 /* IP */
291 ip = (struct ip *)(eth+1);
293 /* We only want IPv4 packets */
294 if (ip->ip_v != 4) {
295 return -1;
297 /* Dont look at fragments */
298 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
299 return -1;
301 /* we only want TCP */
302 if (ip->ip_p != IPPROTO_TCP) {
303 return -1;
306 /* make sure its not a short packet */
307 if (offsetof(struct tcphdr, th_ack) + 4 +
308 (ip->ip_hl*4) > ret) {
309 return -1;
311 /* TCP */
312 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
314 /* tell the caller which one we've found */
315 src->ip.sin_family = AF_INET;
316 src->ip.sin_addr.s_addr = ip->ip_src.s_addr;
317 src->ip.sin_port = tcp->th_sport;
318 dst->ip.sin_family = AF_INET;
319 dst->ip.sin_addr.s_addr = ip->ip_dst.s_addr;
320 dst->ip.sin_port = tcp->th_dport;
321 *ack_seq = tcp->th_ack;
322 *seq = tcp->th_seq;
325 return 0;
326 #ifndef ETHERTYPE_IP6
327 #define ETHERTYPE_IP6 0x86dd
328 #endif
329 } else if (eth->ether_type == htons(ETHERTYPE_IP6)) {
330 /* IP6 */
331 ip6 = (struct ip6_hdr *)(eth+1);
333 /* we only want TCP */
334 if (ip6->ip6_nxt != IPPROTO_TCP) {
335 return -1;
338 /* TCP */
339 tcp = (struct tcphdr *)(ip6+1);
341 /* tell the caller which one we've found */
342 src->ip6.sin6_family = AF_INET6;
343 src->ip6.sin6_port = tcp->th_sport;
344 src->ip6.sin6_addr = ip6->ip6_src;
346 dst->ip6.sin6_family = AF_INET6;
347 dst->ip6.sin6_port = tcp->th_dport;
348 dst->ip6.sin6_addr = ip6->ip6_dst;
350 *ack_seq = tcp->th_ack;
351 *seq = tcp->th_seq;
353 return 0;
356 return -1;
360 bool ctdb_sys_check_iface_exists(const char *iface)
362 /* FIXME AIX: Interface always considered present */
363 return true;
366 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
368 struct peercred_struct cr;
369 socklen_t crl = sizeof(struct peercred_struct);
370 int ret;
371 if ((ret = getsockopt(fd, SOL_SOCKET, SO_PEERID, &cr, &crl) == 0)) {
372 *peer_pid = cr.pid;
374 return ret;
377 char *ctdb_get_process_name(pid_t pid)
379 /* FIXME AIX: get_process_name not implemented */
380 return NULL;
383 int ctdb_set_process_name(const char *name)
385 /* FIXME AIX: set_process_name not implemented */
386 return -ENOSYS;
389 bool ctdb_get_lock_info(pid_t req_pid, struct ctdb_lock_info *lock_info)
391 /* FIXME AIX: get_lock_info not implemented */
392 return false;
395 bool ctdb_get_blocker_pid(struct ctdb_lock_info *reqlock, pid_t *blocker_pid)
397 /* FIXME AIX: get_blocker_pid not implemented */
398 return false;