27 *ifipnext = ifi; /* предыдущий указатель указывал на эту
структуру */
28 ifipnext = &ifi->ifi_next; /* указатель на следующую структуру */
29 ifi->ifi_flags = flags;
30 if (sa->sa_family == AF_LINK) {
31 sdl = (struct sockaddr_dl*)sa;
32 ifi->ifi_index = sdl->sdl_index;
33 if (sdl->sdl_nlen > 0)
34 snprintf(ifi->ifi_name, IFI_NAME, "%*s",
35 sdl->sdl_nlen, &sdl->sdl_data[0]);
36 else
37 snprintf(ifi->ifi_name, IFI_NAME, "index %d",
38 sdl->sdl_index);
39 if ((ifi->ifi_hlen = sdl->sdl_alen) > 0)
40 memcpy(ifi->ifi_haddr, LLADDR(sdl),
41 min(IFI_HADDR, sdl->sdl_alen));
42 }
43 }
6-14
Мы объявляем локальные переменные и затем вызываем нашу функцию net_rt_iflist
.
17-19
Цикл for
— это цикл по всем сообщениям маршрутизации, попадающим в буфер в результате выполнения функции sysctl
. Мы предполагаем, что сообщение — это структура if_msghdr
, и рассматриваем поле ifm_type
(вспомните, что первые три элемента трех структур идентичны, поэтому все равно, какую из трех структур мы используем для просмотра типа элемента).
Проверка, включен ли интерфейс
20-22
Для каждого интерфейса возвращается структура RTM_IFINFO
. Если интерфейс не активен, он игнорируется.
Определение, какие структуры адреса сокета присутствуют
23-24
sa
указывает на первую структуру адреса сокета, следующую за структурой if_msghdr
. Наша функция get_rtaddrs инициализирует массив rti_info
в зависимости от того, какие структуры адреса сокета присутствуют.
Обработка имени интерфейса
25-42
Если присутствует структура адреса сокета с именем интерфейса, в памяти размещается структура ifi_info
и хранятся флаги интерфейса. Предполагаемым семейством этой структуры адреса сокета является AF_LINK
, что означает структуру адреса сокета канального уровня. Если элемент sdl_ nlen
ненулевой, имя интерфейса копируется в структуру ifi_info
. В противном случае в качестве имени хранится строка, содержащая индекс интерфейса. Если элемент sdl_alen
ненулевой, аппаратный адрес (например, адрес Ethernet) копируется в структуру ifi_info
, а его длина также возвращается как ifi_hlen
.
В листинге 18.10 показана вторая часть нашей функции get_ifi_info
, которая возвращает IP-адреса для интерфейса.
Листинг 18.10. Функция get_ifi_info, вторая часть
//route/get_ifi_info.c
44 } else if (ifm->ifm_type == RTM_NEWADDR) {
45 if (ifi->ifi_addr) { /* уже имеется IP-адрес для интерфейса */
46 if (doaliases == 0)
47 continue;
48 /* у нас имеется новый IP-адрес для существующего интерфейса */
49 ifisave = ifi;
50 ifi = Calloc(1, sizeof(struct ifi_info));
51 *ifipnext = ifi; /* предыдущий указатель указывал на эту
структуру */
52 ifipnext = &ifi->ifi_next; /* указатель на следующую структуру */
53 ifi->ifi_flags = ifi_save->ifi_flags;
54 ifi->ifi_index = ifisave->ifi_index;
55 ifi->ifi_hlen = ifisave->ifi_hlen;
56 memcpy(ifi->ifi_name, ifisave->ifi_name, IFI_NAME);
57 memcpy(ifi->ifi_haddr, ifisave->ifi_haddr, IFI_HADDR);
58 }
59 ifam = (struct ifa_msghdr*)next;
60 sa = (struct sockaddr*)(ifam + 1);
61 get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
62 if ((sa = rti_infо[RTAX_IFA]) != NULL) {
63 ifi->ifi_addr = Calloc(1, sa->sa_len);
64 memcpy(ifi->ifi_addr, sa, sa->sa_len);
65 }
66 if ((flags & IFF_BROADCAST) && (sa = rti_infо[RTAX_BRD]) |= NULL) {
67 ifi->ifi_brdaddr = Calloc(1, sa->sa_len);
68 memcpy(ifi->ifi_brdaddr, sa, sa->sa_len);
69 }
70 if ((flags & IFF_POINTOPOINT) &&
71 (sa = rti_infо[RTAX_BRD]) != NULL) {
72 ifi->ifi_dstaddr = Calloc(1, sa->sa_len);
73 memcpy(ifi->ifi_dstaddr, sa, sa->sa_len);
74 }
75 } else
76 err_quit("unexpected message type %d", ifm->ifm_type);
77 }
78 /* "ifihead" указывает на первую структуру в связном списке */
79 return (ifihead); /* указатель на первую структуру в связном списке */
80 }
Возвращение IP-адресов
44-65
Сообщение RTM_NEWADDR
возвращается функцией sysctl
для каждого адреса, связанного с интерфейсом: для первичного адреса и для всех альтернативных имен (псевдонимов). Если мы уже заполнили IP-адрес для этого интерфейса, то мы имеем дело с альтернативным именем. Поэтому если вызывающему процессу нужен адрес псевдонима, мы должны выделить память для другой структуры ifi_info
, скопировать заполненные поля и затем заполнить возвращенный адрес.
Возвращение широковещательного адреса и адреса получателя
66-75
Если интерфейс поддерживает широковещательную передачу, возвращается широковещательный адрес, а если интерфейс является интерфейсом типа «точка-точка», возвращается адрес получателя.
Читать дальше
Конец ознакомительного отрывка
Купить книгу