1 /* 2 * xfrm6_state.c: based on xfrm4_state.c 3 * 4 * Authors: 5 * Mitsuru KANDA @USAGI 6 * Kazunori MIYAZAWA @USAGI 7 * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 8 * IPv6 support 9 * YOSHIFUJI Hideaki @USAGI 10 * Split up af-specific portion 11 * 12 */ 13 14 #include <net/xfrm.h> 15 #include <linux/pfkeyv2.h> 16 #include <linux/ipsec.h> 17 #include <net/ipv6.h> 18 #include <net/addrconf.h> 19 20 static struct xfrm_state_afinfo xfrm6_state_afinfo; 21 22 static void 23 __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, 24 struct xfrm_tmpl *tmpl, 25 xfrm_address_t *daddr, xfrm_address_t *saddr) 26 { 27 /* Initialize temporary selector matching only 28 * to current session. */ 29 ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst); 30 ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src); 31 x->sel.dport = xfrm_flowi_dport(fl); 32 x->sel.dport_mask = htons(0xffff); 33 x->sel.sport = xfrm_flowi_sport(fl); 34 x->sel.sport_mask = htons(0xffff); 35 x->sel.prefixlen_d = 128; 36 x->sel.prefixlen_s = 128; 37 x->sel.proto = fl->proto; 38 x->sel.ifindex = fl->oif; 39 x->id = tmpl->id; 40 if (ipv6_addr_any((struct in6_addr*)&x->id.daddr)) 41 memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr)); 42 memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); 43 if (ipv6_addr_any((struct in6_addr*)&x->props.saddr)) 44 memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); 45 x->props.mode = tmpl->mode; 46 x->props.reqid = tmpl->reqid; 47 x->props.family = AF_INET6; 48 } 49 50 static int 51 __xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n) 52 { 53 int i; 54 int j = 0; 55 56 /* Rule 1: select IPsec transport except AH */ 57 for (i = 0; i < n; i++) { 58 if (src[i]->props.mode == XFRM_MODE_TRANSPORT && 59 src[i]->id.proto != IPPROTO_AH) { 60 dst[j++] = src[i]; 61 src[i] = NULL; 62 } 63 } 64 if (j == n) 65 goto end; 66 67 /* Rule 2: select MIPv6 RO or inbound trigger */ 68 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 69 for (i = 0; i < n; i++) { 70 if (src[i] && 71 (src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION || 72 src[i]->props.mode == XFRM_MODE_IN_TRIGGER)) { 73 dst[j++] = src[i]; 74 src[i] = NULL; 75 } 76 } 77 if (j == n) 78 goto end; 79 #endif 80 81 /* Rule 3: select IPsec transport AH */ 82 for (i = 0; i < n; i++) { 83 if (src[i] && 84 src[i]->props.mode == XFRM_MODE_TRANSPORT && 85 src[i]->id.proto == IPPROTO_AH) { 86 dst[j++] = src[i]; 87 src[i] = NULL; 88 } 89 } 90 if (j == n) 91 goto end; 92 93 /* Rule 4: select IPsec tunnel */ 94 for (i = 0; i < n; i++) { 95 if (src[i] && 96 (src[i]->props.mode == XFRM_MODE_TUNNEL || 97 src[i]->props.mode == XFRM_MODE_BEET)) { 98 dst[j++] = src[i]; 99 src[i] = NULL; 100 } 101 } 102 if (likely(j == n)) 103 goto end; 104 105 /* Final rule */ 106 for (i = 0; i < n; i++) { 107 if (src[i]) { 108 dst[j++] = src[i]; 109 src[i] = NULL; 110 } 111 } 112 113 end: 114 return 0; 115 } 116 117 static int 118 __xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n) 119 { 120 int i; 121 int j = 0; 122 123 /* Rule 1: select IPsec transport */ 124 for (i = 0; i < n; i++) { 125 if (src[i]->mode == XFRM_MODE_TRANSPORT) { 126 dst[j++] = src[i]; 127 src[i] = NULL; 128 } 129 } 130 if (j == n) 131 goto end; 132 133 /* Rule 2: select MIPv6 RO or inbound trigger */ 134 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 135 for (i = 0; i < n; i++) { 136 if (src[i] && 137 (src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION || 138 src[i]->mode == XFRM_MODE_IN_TRIGGER)) { 139 dst[j++] = src[i]; 140 src[i] = NULL; 141 } 142 } 143 if (j == n) 144 goto end; 145 #endif 146 147 /* Rule 3: select IPsec tunnel */ 148 for (i = 0; i < n; i++) { 149 if (src[i] && 150 (src[i]->mode == XFRM_MODE_TUNNEL || 151 src[i]->mode == XFRM_MODE_BEET)) { 152 dst[j++] = src[i]; 153 src[i] = NULL; 154 } 155 } 156 if (likely(j == n)) 157 goto end; 158 159 /* Final rule */ 160 for (i = 0; i < n; i++) { 161 if (src[i]) { 162 dst[j++] = src[i]; 163 src[i] = NULL; 164 } 165 } 166 167 end: 168 return 0; 169 } 170 171 static struct xfrm_state_afinfo xfrm6_state_afinfo = { 172 .family = AF_INET6, 173 .owner = THIS_MODULE, 174 .init_tempsel = __xfrm6_init_tempsel, 175 .tmpl_sort = __xfrm6_tmpl_sort, 176 .state_sort = __xfrm6_state_sort, 177 .output = xfrm6_output, 178 }; 179 180 void __init xfrm6_state_init(void) 181 { 182 xfrm_state_register_afinfo(&xfrm6_state_afinfo); 183 } 184 185 void xfrm6_state_fini(void) 186 { 187 xfrm_state_unregister_afinfo(&xfrm6_state_afinfo); 188 } 189 190